Най-добри практики за улесняване на събирането на боклука в .Net

В Microsoft.Net събирането на боклук е механизъм, приет от Common Language Runtime (CLR) за почистване на ресурсите, консумирани от вашето приложение. Когато създавате обекти в .Net, те се съхраняват в управляваната купчина. Докато трябва да създавате обекти, в повечето случаи не е нужно да се притеснявате от почистването на обектите - времето за изпълнение ще го направи вместо вас.

Трябва обаче да възприемете най-добрите практики във вашето приложение, за да улесните събирането на боклука и да му помогнете да изчисти ресурсите по-бързо. Въпреки че .Net е вещ в възстановяването на управлявани обекти, трябва да следвате определени насоки, за да улесните по-бързото събиране на боклука, за да подобрите производителността на вашето приложение. В тази статия бих искал да представя дискусия за това как работи събирането на боклука и най-добрите практики, свързани с улесняването на събирането на боклука в .Net.

Кога се извършва събирането на боклука?

Събирането на боклука се извършва, когато системата има малко налична физическа памет или GC.Collect()методът е изрично извикан в кода на вашето приложение. Обектите, които вече не се използват или са недостъпни от корена, са кандидати за събиране на боклука. По същество събирачът на боклук почиства паметта, заета от обекти, които нямат препратки.

Поколения

Времетраенето организира управляваната купчина в поколения. Той използва тези поколения за организиране на краткотрайни и дълготрайни обекти. Трябва да се отбележи, че боклукът работи много по-често при по-ниските поколения, отколкото при по-високите. Поколение 0 съдържа краткотрайни обекти като временни обекти. Когато обектът е създаден, той се съхранява в поколение 0, освен ако не е голям обект. Ако обектът е голям обект, той се съхранява в Голямата купчина обекти (LOH) в поколение 2. В повечето случаи обектите от поколение 0 се възстановяват от събирача на боклук, когато работи във фонов режим.

Когато пишете код, трябва да се придържате към някои най-добри практики. Като пример, трябва да създадете обекти в локалния обхват, доколкото е възможно, за да улесните събирането на боклука. Обектите, които са създадени в по-голям обхват, обикновено се съхраняват в паметта за по-дълъг период от време. Можете да се възползвате от CLR профилиращия инструмент, за да разберете моделите на разпределение на вашето приложение.

Трябва да избягвате извикването на GC.Collect()метода, тъй като той причинява пълна колекция от всички поколения (поколение 0, 1 и 2). Когато извикате GC.Collect()метода, изпълнението посещава всички живи обекти във вашето приложение. Това отнема значително време и следователно е много скъпа операция. В резултат на това не е добра практика да се извиква GC.Collect()методът.

Ако трябва да извикате GC.Collect()метода, трябва да се обадите GC.WaitForPendingFinalizers()след повикването, за GC.Collect()да сте сигурни, че текущата изпълняваща нишка чака, докато финализаторите за всички обекти бъдат изпълнени.

След това трябва отново да се обадите на GC.Collect()метода, за да сте сигурни, че събирате останалите мъртви предмети. Тези мъртви обекти, които може да са били създадени поради извикването на метода на финализатора на обектите. Следният кодов фрагмент показва как се използват тези методи.

System.GC.Collect();

System.GC.WaitForPendingFinalizers();

System.GC.Collect();

Трябва да се уверите, че свеждате до минимум скритите разпределения и пишете кода си по такъв начин, че да се елиминират шансовете за промоция на краткотрайни обекти към по-високите поколения. Не трябва да препращате краткотрайни обекти от дълготрайните, за да избегнете популяризирането на краткотрайните обекти сред по-високите поколения.

Също така трябва да избягвате да пишете финализатори за вашите класове. Ако имате финализатор, внедрен във вашия клас, обектите от такива класове ще се превърнат в дълготрайни обекти, тъй като времето за изпълнение трябва да популяризира финализируемите обекти сред по-старите поколения. Трябва да зададете на обекти нула, преди да извършите продължително повикване, ако такива обекти не са необходими на приложението. Ако вече не се нуждаете от статичен обект или други обекти във вашето приложение, трябва да го зададете на null, преди да извършите продължително повикване. Не трябва да задавате на локални променливи нула, тъй като не е необходима; времето за изпълнение може да определи кой локален обект не е посочен във вашия код или не се използва повече, така че не е необходимо да задавате локална променлива да нулира изрично.