Automatická správa paměti
Automatická správa paměti je jedna ze služeb, kterou modul CLR (Common Language Runtime) poskytuje během Managed Execution. Systém uvolňování paměti modulu CLR (Common Language Runtime) spravuje přidělování a uvolňování paměti pro aplikace. Pro vývojáře to znamená, že není nutné při vývoji spravované aplikace psát kód provádějící úlohy správy paměti. Automatická správa paměti může eliminovat běžné problémy, například zapomenutí volného objektu způsobující úniky paměti nebo pokusy o přístup k paměti v případě objektu, který již byl uvolněn. Tento oddíl popisuje, jak systém uvolňování paměti přiděluje a uvolňuje paměť.
Přidělování paměti
Když inicializujete nový proces, runtime modul vyhradí souvislou oblast adresního prostoru pro tento proces. Tento vyhrazený prostor se nazývá spravovaná halda. Spravovaná halda uchovává ukazatel na adresu, kde bude v haldě alokován další objekt. Zpočátku je tento ukazatel nastaven na základní adresu spravované haldy. Všechny reference types jsou přidělovány na spravované haldě. Když aplikace vytvoří první odkazový typ, je pro tento typ alokována paměť na základní adrese spravované haldy. Když aplikace vytvoří další objekt, systém uvolňování paměti přidělí paměť pro něj v adresním prostoru bezprostředně za prvním objektem. Dokud je dostupný adresní prostor, systém uvolňování paměti nadále přiděluje prostor pro nové objekty tímto způsobem.
Přidělování paměti ze spravované haldy je rychlejší než nespravované přidělování paměti. Vzhledem k tomu, že runtime modul přiděluje paměť pro objekt přidáním hodnoty k ukazateli, je téměř tak rychlá jako přidělování paměti ze zásobníku. Navíc nové objekty, které jsou alokovány postupně, jsou uloženy souvisle ve spravované haldě, proto aplikace může přistupovat k objektům velmi rychle.
Uvolňování paměti
Optimalizující engine systému uvolňování paměti určuje nejvhodnější čas k provedení sběru, založeného na tom, jak byla provedena alokace. Když systém uvolňování paměti provádí sběr, uvolňuje paměť objektů, které již nejsou používány aplikací. Určuje, které objekty již nejsou používány zkoumáním kořenů aplikace. Každá aplikace má množinu kořenů. Každý kořen buď odkazuje na objekt ve spravované haldě nebo je nastaven na hodnotu null. Kořeny aplikace obsahují globální a statické ukazatele objektu, místní proměnné, parametry referenčního objektu na zásobník vlákna a registry procesoru. Systém uvolňování paměti má přístup k seznamu aktivních kořenů, které just-in-time (JIT) compiler a runtime modul udržují. Pomocí tohoto seznamu zkoumá kořeny aplikace a v procesu vytvoří graf, který obsahuje všechny objekty, které jsou dostupné z kořenů.
Objekty, které nejsou v grafu, jsou nedostupné z kořenů aplikace. Systém uvolňování paměti považuje nedosažitelné objekty za odpad a uvolní paměť, která jim byla alokována. Během sběru systém uvolňování paměti zkoumá spravovanou haldu, hledá bloky adresního prostoru obsazené nedosažitelnými objekty. Jak objeví nedostupný objekt, použije funkci kopírování paměti k setřepání dosažitelných objektů v paměti, uvolňováním bloků adresního prostoru přiděleného nedosažitelným objektům. Jakmile byla paměť pro dosažitelné objekty setřepána, systém uvolňování paměti provede nezbytné korekce ukazatele, aby kořeny aplikace směřovaly na objekty v jejich novém umístění. Také umístí ukazatel spravované haldy za poslední dostupný objekt. Všimněte si, že paměť je setřepána pouze v případě, že sběr zjistí významný počet nedosažitelných objektů. Jestliže všechny objekty ve spravované haldě přežijí sběr, pak setřepání paměti není nutné.
Pro zvýšení výkonu, runtime modul přiděluje paměť pro velké objekty v samostatné haldě. Systém uvolňování paměti automaticky uvolňuje paměť pro velké objekty. Nicméně kvůli zabránění přesouvání velkých objektů v paměti, tato paměť není setřepána.
Generace a výkon
Z důvodu optimalizace výkonu systému uvolňování paměti je spravovaná halda rozdělena do tří generací: 0, 1 a 2. Algoritmus systému uvolňování paměti modulu runtime je založen na několika generalizacích, které průmysl počítačového softwaru objevil jako pravdivé pomocí experimentování se schématy systému uvolňování paměti. První, je rychlejší setřepat paměť pro část spravované haldy než pro celou spravovanou haldu. Za druhé, novější objekty budou mít kratší životnost a starší objekty budou mít delší životnost. Poslední, novější objekty mají tendenci být vzájemně spojené a přistupované aplikací přibližně ve stejnou dobu.
Systém uvolňování paměti modulu runtime ukládá nové objekty v generaci 0. Objekty vytvořené dříve v době života dané aplikace, které přežijí sběr, jsou povýšeny a uloženy v generacích 1 a 2. Proces povýšení objektu je popsán dále v tomto tématu. Protože je rychlejší setřepat část spravované haldy než celou haldu, umožňuje toto schéma systému uvolňování paměti uvolnit paměť v konkrétní generaci, spíše než uvolnit paměť pro celou spravovanou haldu pokaždé, když provádí sběr.
Ve skutečnosti systém uvolňování paměti provádí sběr při zaplnění generace 0. Pokud se aplikace pokusí vytvořit nový objekt, když je generace 0 plná, systém uvolňování paměti zjistí, že zde v generaci 0 není žádný zbývající adresní prostor, který by bylo možno alokovat pro objekt. Systém uvolňování paměti provádí sběr ve snaze uvolnit adresní prostor pro objekt v generaci 0. Systém uvolňování paměti začne prověřením objektů v generaci 0, spíše než ověřením všech objektů ve spravované haldě. Toto je nejvhodnější přístup, protože nové objekty inklinují ke kratší životnosti a očekává se, že mnoho objektů v generaci 0 nebude nadále používáno aplikací, když se provádí sběr. Kromě toho sběr samotné generace 0 často získá dostatek paměti pro umožnění aplikaci pokračovat ve vytváření nových objektů.
Poté, co systém uvolňování paměti provede sběr generace 0, setřepe paměť pro dosažitelné objekty, jak je vysvětleno v části Uvolňování paměti dříve v tomto tématu. Systém uvolňování paměti potom povýší tyto objekty a považuje tuto část spravované haldy za generaci 1. Protože objekty, které přežijí sběr mají tendenci mít delší životnost, má smysl povýšit je do vyšší generace. V důsledku toho systém uvolňování paměti nemusí znovu přezkoumat objekty v generacích 1 a 2 pokaždé, když provádí sběr generace 0.
Poté, co systém uvolňování paměti provede první sběr generace 0 a povýší dosažitelné objekty na generaci 1, považuje zbytek spravované haldy za generaci 0. Pokračuje v alokování paměti pro nové objekty v generaci 0, dokud generace 0 není plná a je nezbytné provést další sběr. V tomto okamžiku optimalizující engine systému uvolňování paměti určí, zda je nezbytné přezkoumat objekty ve starších generacích. Například, pokud sběr generace 0 nezíská dostatek paměti pro aplikaci, aby mohla úspěšně dokončit pokus vytvořit nový objekt, tak systém uvolňování paměť může provést sběr generace 1 a poté generace 2. Pokud tohle nezíská dostatek paměti, systém uvolňování paměti může provádět sběr generací 2, 1 a 0. Po každém sběru systém uvolňování paměti setřepe dosažitelné objekty v generaci 0 a povýší je do generace 1. Objekty v generaci 1, které přežijí sběry jsou povýšeny do generace 2. Vzhledem k tomu, že systém uvolňování paměti podporuje pouze tři generace, objekty v generaci 2, které přežijí sběr, zůstanou v generaci 2, dokud nejsou v budoucím sběru určené jako nedosažitelné.
Uvolňování paměti pro nespravované prostředky
U většinu objektů, které vytváří vaše aplikace se můžete spolehnout na systém uvolňování paměti, který automaticky vykonává nutné úkoly správy paměti. Nespravované prostředky však vyžadují explicitní vyčištění. Nejběžnější typ nespravovaného prostředku je objekt, který obaluje prostředek operačního systému, například popisovač souboru, popisovač okna nebo síťové připojení. I když systém uvolňování paměti je schopen sledovat dobu života spravovaného objektu, který zapouzdřuje nespravovaný prostředek, nemá specifické znalosti o tom, jak zdroj vyčistit. Když vytvoříte objekt, který zapouzdřuje nespravovaný prostředek, je vhodné poskytnout nezbytný kód pro vyčištění nespravovaného prostředku ve veřejné metodě Dispose. Poskytnutím metody Dispose umožníte uživatelům vašeho objektu explicitně uvolnit jeho paměť, když jsou s objektem hotovi. Použijete-li objekt, který zapouzdřuje nespravovaný prostředek, měli byste znát metodu Dispose a volat ji podle potřeby. Další informace o čištění nespravovaných prostředků a příklad návrhového vzoru pro implementování metody Dispose, naleznete v tématu Garbage Collection.