Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V modulu CLR (Common Language Runtime) slouží garbage collector (GC) jako automatický správce paměti. Správce paměti (garbage collector) řídí přidělení a uvolnění paměti pro aplikaci. Vývojáři, kteří pracují se spravovaným kódem, proto nemusí psát kód pro provádění úloh správy paměti. Automatická správa paměti může eliminovat běžné problémy, jako je například zapomenutí uvolnit objekt a způsobit nevracení paměti nebo pokus o přístup k uvolněné paměti pro objekt, který je již uvolněn.
Tento článek popisuje základní koncepty správy paměti.
Zaměstnanecké výhody
Garbage Collector poskytuje následující výhody:
Uvolňuje vývojáře z nutnosti ručně uvolňovat paměť.
Efektivně přiděluje objekty na spravované haldě.
Uvolní objekty, které se už nepoužívají, vymaže jejich paměť a zachová paměť dostupnou pro budoucí přidělení. Spravované objekty automaticky získají čistý obsah, takže jejich konstruktory nemusí inicializovat každé datové pole.
Poskytuje bezpečnost paměti tím, že zajistí, že objekt nemůže použít pro sebe paměť přidělenou jinému objektu.
Základy paměti
Následující seznam shrnuje důležité koncepty paměti CLR:
Každý proces má svůj vlastní samostatný virtuální adresní prostor. Všechny procesy na stejném počítači sdílejí stejnou fyzickou paměť a stránkační soubor, pokud existuje.
Ve výchozím nastavení má každý proces na 32bitových počítačích virtuální adresní prostor v uživatelském režimu 2 GB.
Jako vývojář aplikací pracujete jenom s virtuálním adresní prostorem a nikdy nebudete manipulovat s fyzickou pamětí přímo. Systém uvolňování paměti pro vás přidělí a uvolní virtuální paměť na spravované haldě.
Pokud píšete nativní kód, můžete pomocí funkcí Systému Windows pracovat s virtuálním adresní prostorem. Tyto funkce přidělují a uvolní virtuální paměť pro vás na nativních haldách.
Virtuální paměť může být ve třech stavech:
Stát Popis Free Blok paměti nemá žádné odkazy na něj a je k dispozici pro přidělení. Rezervováno Blok paměti je k dispozici pro vaše použití a nedá se použít pro žádné jiné žádosti o přidělení. Do tohoto bloku paměti ale nemůžete ukládat data, dokud nebudou potvrzena. Zavázáno Blok paměti je přiřazen k fyzickému úložišti. Virtuální adresní prostor se může fragmentovat, což znamená, že v adresní prostoru jsou volné bloky označované jako díry. Když se požaduje přidělení virtuální paměti, musí správce virtuální paměti najít jeden volný blok, který je dostatečně velký, aby vyhovoval žádosti o přidělení. I v případě, že máte 2 GB volného místa, přidělení, které vyžaduje 2 GB, bude neúspěšné, pokud není veškeré volné místo v jednom bloku adres.
Pokud není dostatek virtuálního adresního prostoru k rezervaci, nebo fyzického prostoru k alokaci, může dojít k nedostatku paměti.
Stránkový soubor se používá, i když je nízké zatížení fyzické paměti (poptávka po fyzické paměti). Při prvním vysokém zatížení fyzické paměti musí operační systém vytvořit místo ve fyzické paměti pro ukládání dat a zálohuje některá data, která jsou ve fyzické paměti, do stránkového souboru. Data nejsou stránkována, dokud nejsou potřeba, takže je možné narazit na stránkování při nízkém tlaku na fyzickou paměť.
Přidělení paměti
Při inicializaci nového procesu si modul runtime vyhrazuje souvislou oblast adresního prostoru procesu. Tento vyhrazený adresní prostor se nazývá spravovaná halda. Spravovaná halda udržuje ukazatel na adresu, kde bude přidělen další objekt v haldě. Zpočátku je tento ukazatel nastavený na základní adresu spravované haldy. Všechny odkazové typy se přidělují na spravované haldě. Když aplikace vytvoří první referenční typ, paměť je přidělena pro typ na vstupní adrese spravované haldy. Když aplikace vytvoří další objekt, modul runtime pro něj přidělí paměť v adresního prostoru bezprostředně za prvním objektem. Pokud je adresní prostor k dispozici, modul runtime tímto způsobem přiděluje prostor pro nové objekty.
Přidělování paměti ze spravované haldy je rychlejší než přidělení nespravované paměti. Vzhledem k tomu, že modul runtime přiděluje paměť objektu přidáním hodnoty ukazatele, je téměř stejně rychlé jako přidělení paměti ze zásobníku. Kromě toho, protože nové objekty, které jsou přiděleny po sobě jdoucí, jsou uloženy souvisle ve spravované haldě, může aplikace přistupovat k objektům rychle.
Uvolnění paměti
Optimalizační mechanismus garbage collectoru určuje nejlepší čas pro provedení sběru paměti na základě aktuálních přidělení. Když garbage collector provádí sběr, uvolní paměť pro objekty, které už aplikace nepoužívá. Určuje, které objekty se už nepoužívají prozkoumáním kořenového adresáře aplikace. Kořeny aplikace zahrnují statická pole, místní proměnné v zásobníku vlákna, registry procesoru, GC objekty a frontu finalizace. Každý kořenový adresář buď odkazuje na objekt ve spravované haldě, nebo je nastaven na hodnotu null. Garbage collector může požádat zbytek runtime pro tyto kořeny. Systém uvolňování paměti používá tento seznam k vytvoření grafu obsahujícího všechny objekty, které jsou dosažitelné z kořenů.
Objekty, které nejsou v grafu, jsou nedostupné z kořenového adresáře aplikace. Systém správy paměti považuje nedostupné objekty za nepotřebné a uvolňuje jim přidělenou paměť. Během sběru garbage collector zkoumá spravovanou haldu a hledá bloky adresního prostoru obsazené nedostupnými objekty. Když zjistí každý nedostupný objekt, využívá funkci kopírování paměti ke komprimování dosažitelných objektů v paměti a uvolní bloky adresních prostorů přidělených nedostupným objektům. Jakmile je paměť pro dosažitelné objekty kompaktována, garbage collector provede potřebné opravy ukazatelů tak, aby aplikační kořeny odkazovaly na objekty v jejich nových umístěních. Umístí také ukazatel spravované haldy za poslední dosažitelný objekt.
Paměť je komprimována pouze v případě, že kolekce zjistí významný počet nedostupných objektů. Pokud všechny objekty ve spravované haldě přežijí kolekci, není potřeba komprimovat paměť.
Aby se zlepšil výkon, modul runtime přidělí paměť pro velké objekty v samostatné haldě. Garbage collector automaticky uvolní paměť pro velké objekty. Pokud se ale chcete vyhnout přesouvání velkých objektů v paměti, není tato paměť obvykle komprimovaná.
Podmínky pro garbage collection
K uvolňování paměti dochází v případě, že platí jedna z následujících podmínek:
Systém má malou fyzickou paměť. Velikost paměti je zjištěna oznámením o nedostatku paměti z operačního systému nebo nedostatkem paměti, jak je uvedeno hostitelem.
Paměť, kterou používají přidělené objekty ve spravované haldě, překračuje přijatelnou prahovou hodnotu. Tato prahová hodnota se průběžně upravuje při spuštění procesu.
Volá se GC.Collect metoda. V téměř všech případech nemusíte tuto metodu volat, protože systém uvolňování paměti běží nepřetržitě. Tato metoda se primárně používá pro jedinečné situace a testování.
Spravovaná halda
Po inicializaci modulu CLR uvolňování paměti přidělí segment paměti pro ukládání a správu objektů. Tato paměť se nazývá spravovaná halda, nikoli nativní halda v operačním systému.
Pro každý spravovaný proces existuje spravovaná halda. Všechna vlákna procesu přidělují paměť pro objekty ve stejné haldě.
Pro rezervaci paměti volá garbage collector Windows funkci VirtualAlloc a vyhrazuje jeden segment paměti najednou pro spravované aplikace. Garbage collector také dle potřeby rezervuje segmenty a uvolňuje segmenty zpět do operačního systému (po odstranění všech objektů) voláním funkce Windows VirtualFree.
Důležité
Velikost segmentů přidělených systémem uvolňování paměti je specifická pro implementaci a může se kdykoli změnit, a to i při pravidelných aktualizacích. Vaše aplikace by nikdy neměla provádět předpoklady týkající se konkrétní velikosti segmentu ani záviset na ní, ani by se neměla pokoušet konfigurovat množství paměti dostupné pro přidělení segmentů.
Čím méně objektů alokovaných na haldě, tím méně práce musí garbage collector provést. Při přidělování objektů nepoužívejte zaokrouhlené hodnoty, které překračují vaše potřeby, například přidělení pole 32 bajtů, pokud potřebujete jenom 15 bajtů.
Když je spuštěno uvolňování paměti, správce paměti uvolní paměť obsazenou mrtvými objekty. Proces znovuzískání komprimuje živé objekty tak, že se přesunou společně, a odstraní mrtvý prostor, čímž se halda zmenší. Tento proces zajišťuje, aby objekty, které jsou přiděleny společně, zůstaly na spravované haldě, aby byla zachována jejich lokalita.
Rušivost (frekvence a doba trvání) uvolňování paměti je výsledkem objemu přidělení a množství přežívající paměti ve spravované haldě.
Haldu lze považovat jako skládání dvou hromad: halda velkých objektů a halda malých objektů. Velká halda objektů obsahuje objekty, které jsou 85 000 bajtů nebo větší, což jsou obvykle pole. Je vzácné, aby objekt instance byl nadměrně velký.
Návod
Můžete nastavit prahovou velikost pro objekty, aby přešly na haldu velkých objektů.
Generace
Algoritmus GC je založen na několika aspektech:
- Je rychlejší komprimovat paměť pro část spravované haldy než pro celou spravovanou haldu.
- Novější objekty mají kratší životnost a starší objekty mají delší životnost.
- Novější objekty se obvykle vzájemně souvisejí a aplikace k němu přistupuje přibližně ve stejnou dobu.
Správa paměti probíhá především při reklamaci krátkožijících objektů. Pro optimalizaci výkonu systému správy paměti je spravovaná halda rozdělena do tří generací, 0, 1 a 2, takže dokáže zpracovávat dlouhodobé a krátkodobé objekty samostatně. Garbage kolektor ukládá nové objekty v generaci 0. Objekty vytvořené v rané fázi životnosti aplikace, které přežijí kolekce, se propagují a ukládají v generacích 1 a 2. Vzhledem k tomu, že je rychlejší zkomprimovat část spravované haldy než celou haldu, tento přístup umožňuje systému pro správu paměti uvolnit paměť v konkrétní generaci, místo uvolnění paměti pro celou spravovanou haldu pokaždé, když provede kolekci.
Generace 0: Tato generace je nejmenší a obsahuje krátkodobé objekty. Příkladem krátkodobého objektu je dočasná proměnná. Proces uvolňování paměti probíhá nejčastěji v této generaci.
Nově přidělené objekty tvoří novou generaci objektů a implicitně generují 0 kolekcí. Pokud se ale jedná o velké objekty, umístí se na haldu velkých objektů (LOH), která se někdy označuje jako generace 3. Generace 3 je fyzická generace, která se logicky shromažďuje jako součást generace 2.
Většina objektů je získána zpět pro sběr odpadu v generaci 0 a nepřežije do další generace.
Pokud se aplikace pokusí vytvořit nový objekt, když je generace 0 plná, systém uvolňování paměti provede kolekci, aby uvolnil adresní prostor objektu. Systém uvolňování paměti začíná zkoumáním objektů ve generaci 0, místo všech objektů ve spravované haldě. Kolekce generace 0 často uvolní dostatek paměti, aby aplikace mohla pokračovat ve vytváření nových objektů.
Generace 1: Tato generace obsahuje krátkodobé objekty a slouží jako vyrovnávací paměť mezi krátkodobými objekty a dlouhodobými objekty.
Jakmile garbage collector provede sběr generace 0, zkompaktuje paměť pro dosažitelné objekty a povýší je do generace 1. Protože objekty, které přežijí kolekce, mají tendenci mít delší životnost, dává smysl je propagovat na vyšší generaci. Garbage collector nemusí pokaždé znovu zkoumat objekty v generacích 1 a 2, když provádí sběr generace 0.
Pokud kolekce generace 0 nevymaže dostatek paměti pro to, aby aplikace mohla vytvořit nový objekt, může garbage collector provést kolekci generace 1 a následně i generace 2. Objekty v generaci 1, které přežijí kolekce, jsou povýšeny na generaci 2.
Generace 2: Tato generace obsahuje dlouhodobé objekty. Příkladem dlouhodobého objektu je objekt v serverové aplikaci, která obsahuje statická data, která jsou aktivní po dobu trvání procesu.
Objekty v generaci 2, které přežijí kolekci, zůstanou v generaci 2, dokud nebudou v budoucí kolekci nedostupné.
Objekty ve velké haldě objektu (která se někdy označuje jako generace 3) se shromažďují také v generaci 2.
Uvolňování paměti probíhá ve specifických generacích, když to podmínky vyžadují. Shromažďování generace znamená shromažďování objektů v této generaci a všech jejích mladších generací. Uvolňování paměti generace 2 se také označuje jako úplné uvolňování paměti, protože uvolní objekty ve všech generacích (tj. všechny objekty ve spravované haldě).
Přežití a propagační akce
Objekty, které nejsou uvolněné v rámci mechanismu garbage collection, se nazývají objekty přeživší a jsou povýšeny na další generaci.
- Objekty, které přežijí uvolňování paměti generace 0, postupují do generace 1.
- Objekty, které přežijí uvolňování paměti generace 1, jsou povýšeny na generaci 2.
- Objekty, které přežijí garbage collection generace 2, zůstanou ve generaci 2.
Když garbage collector zjistí, že míra přežití v generaci je vysoká, zvýší práh alokace pro danou generaci. Další kolekce získává značné množství uvolněné paměti. CLR neustále vyrovnává dvě priority: neumožňuje, aby pracovní sada aplikace byla příliš velká, protože zpožďuje uvolňování paměti a neumožňuje příliš často spustit uvolňování paměti.
Dočasné generace a segmenty
Vzhledem k tomu, že objekty v generacích 0 a 1 jsou krátkodobé, tyto generace se označují jako dočasné generace.
Dočasné generace se přidělují v segmentu paměti, který se označuje jako dočasný segment. Každý nový segment získaný uvolňováním paměti se stane novým dočasným segmentem a obsahuje objekty, které přežily uvolňování paměti generace 0. Starý dočasný segment se stane novým segmentem generace 2.
Velikost efemérního segmentu se liší v závislosti na tom, jestli je systém 32bitový nebo 64bitový a na typu uvolňovače paměti, který používá (pracovní stanice nebo server GC). Následující tabulka uvádí výchozí velikosti dočasného segmentu:
| Pracovní stanice/serverový GC | 32bitová | 64bitová |
|---|---|---|
| Pracovní stanice GC | 16 MB | 256 MB |
| Server GC | 64 MB | 4 GB |
| Serverový GC se 4 > logickými procesory | 32 MB | 2 GB |
| Serverový GC s 8 logickými > procesory | 16 MB | 1 GB |
Dočasný segment může obsahovat objekty generace 2. Objekty generace 2 můžou používat více segmentů, kolik váš proces vyžaduje, a paměť umožňuje.
Velikost uvolněné paměti z pomíjivého čištění paměti je omezená na velikost pomíjivého segmentu. Množství uvolněné paměti je úměrné prostoru, který byly obsazeny mrtvými objekty.
Co se stane během garbage collection (uvolňování paměti)
Uvolňování paměti má následující fáze:
Fáze označení, která najde a vytvoří seznam všech živých objektů.
Změna umístění, která aktualizuje odkazy na objekty komprimované.
Komprimující fáze, která uvolní prostor obsazený mrtvými objekty a zkomprimuje přeživší objekty. Fáze komprimace přesune objekty, které přežily garbage collection, k starší části segmentu.
Vzhledem k tomu, že kolekce generace 2 mohou zabírat více segmentů, lze objekty, které jsou povýšeny do generace 2, přesunuty do staršího segmentu. Přeživší generace 1 i generace 2 je možné přesunout do jiného segmentu, protože jsou povýšeny na generaci 2.
Obvykle není halda velkých objektů (LOH) kompaktována, protože kopírování velkých objektů má negativní vliv na výkon. V .NET Core a v rozhraní .NET Framework 4.5.1 a novější však můžete pomocí GCSettings.LargeObjectHeapCompactionMode vlastnosti komprimovat haldu velkých objektů na vyžádání. Kromě toho je LOH automaticky komprimován, pokud je pevný limit nastaven zadáním:
- Omezení paměti pro kontejner.
- Možnosti konfigurace prostředí runtime GCHeapHardLimit nebo GCHeapHardLimitPercent.
Automatické uvolňování paměti používá následující informace k určení, zda jsou objekty živé:
Stackové kořeny: Proměnné zásobníku poskytované kompilátorem JIT a prohledávačem zásobníku. Optimalizace JIT můžou prodloužit nebo zkrátit oblasti kódu, ve kterých jsou proměnné zásobníku hlášeny systému uvolňování paměti.
Popisovače pro odpadkový sběr: Popisovače, které ukazují na spravované objekty a které mohou být přiděleny uživatelským kódem nebo běhovým prostředím CLR.
Statická data: Statické objekty v doménách aplikace, které můžou odkazovat na jiné objekty. Každá doména aplikace sleduje své statické objekty.
Před spuštěním uvolňování paměti jsou všechna spravovaná vlákna pozastavena s výjimkou vlákna, které aktivovalo uvolňování paměti.
Následující obrázek znázorňuje vlákno, které aktivuje uvolňování paměti a způsobí pozastavení ostatních vláken:
Neběžně spravované prostředky
U většiny objektů, které vaše aplikace vytvoří, můžete při automatickém provádění potřebných úloh správy paměti spoléhat na uvolňování paměti. Nespravované prostředky ale vyžadují explicitní vyčištění. Nejběžnějším typem nespravovaného prostředku je objekt, který obaluje prostředek operačního systému, například popisovač souboru, popisovač okna nebo síťové spojení. Přestože garbage collector může sledovat životnost spravovaného objektu, který zapouzdřuje nespravovaný prostředek, nemá konkrétní znalosti o tom, jak vyčistit tento prostředek.
Když definujete objekt, který zapouzdřuje nespravovaný prostředek, doporučuje se zadat potřebný kód pro vyčištění nespravovaného prostředku ve veřejné Dispose metodě. Poskytnutím Dispose metody povolíte uživatelům objektu explicitně uvolnit prostředek, jakmile s objektem skončí. Pokud používáte objekt, který zapouzdřuje nespravovaný prostředek, nezapomeňte volat Dispose podle potřeby.
Musíte také poskytnout způsob, jak se neřízené zdroje uvolní v případě, že spotřebitel vašeho typu zapomene volat Dispose. Můžete buď použít bezpečný popisovač k zabalení nespravovaného prostředku, nebo přepsat metodu Object.Finalize().
Další informace o čištění nespravovaných prostředků naleznete v tématu Vyčištění nespravovaných prostředků.