Automatická správa paměti

Automatická správa paměti je jednou ze služeb, které modul CLR (Common Language Runtime) poskytuje během spravovaného spouštění. Uvolňování paměti modulu CLR (Common Language Runtime) spravuje přidělení a uvolnění paměti pro aplikaci. Pro vývojáře to znamená, že při vývoji spravovaných aplikací nemusíte 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 paměti pro objekt, který již byl uvolněn. Tato část popisuje, jak systém uvolňování paměti přiděluje a uvolní paměť.

Přidělování 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í typ odkazu, paměť je přidělena pro typ na základní adrese spravované haldy. Když aplikace vytvoří další objekt, systém uvolňování paměti pro něj přidělí paměť v adresního prostoru bezprostředně za prvním objektem. Pokud je adresní prostor k dispozici, systém uvolňování paměti bude tímto způsobem dál přidělovat 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ě, jsou uloženy souvisle ve spravované haldě, může aplikace přistupovat k objektům velmi rychle.

Uvolnění paměti

Optimalizační modul uvolňování paměti určuje nejvhodnější čas k provedení kolekce na základě přidělení. Když uvolňování paměti provede kolekci, 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. Každá aplikace má sadu kořenových certifikátů. Každý kořenový adresář buď odkazuje na objekt ve spravované haldě, nebo je nastaven na hodnotu null. Kořeny aplikace zahrnují statická pole, místní proměnné a parametry v zásobníku vlákna a registru procesoru. Systém uvolňování paměti má přístup k seznamu aktivních kořenových certifikátů, které kompilátor JIT (just-in-time) a modul runtime udržuje. Pomocí tohoto seznamu prozkoumá kořeny aplikace a v procesu vytvoří graf, který obsahuje všechny objekty, které jsou dostupné z kořenových certifikátů.

Objekty, které nejsou v grafu, jsou nedostupné z kořenového adresáře aplikace. Systém uvolňování paměti považuje nedostupné objekty za uvolnění paměti a uvolní paměť přidělenou pro ně. Během shromažďování systém uvolňování paměti zkoumá spravovanou haldu a hledá bloky adresního prostoru obsazeného 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 komprimovaná, systém uvolňování paměti provede potřebné opravy ukazatelů tak, aby kořeny aplikace odkazovaly na objekty v jejich nových umístěních. Umístí také ukazatel spravované haldy za poslední dosažitelný objekt. Všimněte si, že paměť je komprimována pouze v případě, že kolekce zjistí velký 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ě. Uvolňování paměti automaticky uvolní paměť pro velké objekty. Pokud se ale chcete vyhnout přesouvání velkých objektů v paměti, není tato paměť komprimovaná.

Generace a výkon

Pro optimalizaci výkonu uvolňování paměti je spravovaná halda rozdělena do tří generací: 0, 1 a 2. Algoritmus uvolňování paměti modulu runtime je založen na několika generalizacích, které počítačový softwarový průmysl zjistil jako pravdivý experimentováním se schématy uvolňování paměti. Za prvé je rychlejší zkomprimovat 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. Nakonec novější objekty obvykle vzájemně souvisejí a aplikace k němu přistupuje 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é v rané fázi životnosti aplikace, které přežijí kolekce, se propagují a ukládají v generacích 1 a 2. Proces povýšení objektu je popsán dále v tomto tématu. Vzhledem k tomu, že je rychlejší zkomprimovat část spravované haldy než celá halda, umožňuje toto schéma uvolňování paměti uvolnit paměť v konkrétní generaci, a ne uvolnit paměť pro celou spravovanou haldu pokaždé, když provede kolekci.

Ve skutečnosti systém uvolňování paměti provádí kolekci, když je generace 0 plná. Pokud se aplikace pokusí vytvořit nový objekt, když je generace 0 plná, systém uvolňování paměti zjistí, že v generaci 0 neexistuje žádný adresní prostor, který by se pro objekt přidělil. Uvolňování paměti provede kolekci při pokusu o uvolnění adresního prostoru v generaci 0 objektu. Systém uvolňování paměti začíná zkoumáním objektů ve generaci 0, nikoli všemi objekty ve spravované haldě. Jedná se o nejúčinnější přístup, protože nové objekty mají tendenci mít krátké životnosti a očekává se, že mnoho objektů ve generaci 0 již nebude při provádění kolekce používáno aplikací. Kromě toho kolekce generace 0 sama často uvolní dostatek paměti, aby aplikace mohla pokračovat ve vytváření nových objektů.

Jakmile systém uvolňování paměti provede kolekci 0. generace, zkomprimuje paměť pro dosažitelné objekty, jak je vysvětleno v části Uvolnění paměti dříve v tomto tématu. Systém uvolňování paměti pak tyto objekty propaguje a považuje tuto část spravované haldy generace 1. Protože objekty, které přežijí kolekce, mají tendenci mít delší životnost, dává smysl je propagovat na vyšší generaci. V důsledku toho systém uvolňování paměti nemusí rekontaminovat objekty v generacích 1 a 2 pokaždé, když provádí kolekci generace 0.

Jakmile systém uvolňování paměti provede první kolekci generace 0 a podporuje dosažitelné objekty na generaci 1, považuje zbytek spravované generace haldy 0. Nadále přiděluje paměť pro nové objekty v generaci 0, dokud nebude generace 0 plná a je nutné provést další kolekci. V tomto okamžiku optimalizační modul uvolňování paměti určuje, zda je nutné prozkoumat objekty ve starších generacích. Pokud například kolekce generace 0 nevyvolá dostatek paměti, aby aplikace úspěšně dokončila svůj pokus o vytvoření nového objektu, uvolňování paměti může provést kolekci generace 1, pak generace 2. Pokud se tím nevyvolá dostatek paměti, systém uvolňování paměti může provést kolekci generací 2, 1 a 0. Po každé kolekci systém uvolňování paměti zkomprimuje dosažitelné objekty v generaci 0 a podporuje je na generaci 1. Objekty v generaci 1, které přežijí kolekce, jsou povýšeny na generaci 2. Vzhledem k tomu, že systém uvolňování paměti podporuje pouze tři generace, zůstanou objekty v generaci 2, které přežijí kolekci ve 2. generaci, dokud nebudou v budoucí kolekci nedostupné.

Uvolnění paměti pro nespravované prostředky

U většiny objektů, které vaše aplikace vytvoří, můžete spoléhat na uvolňování paměti, abyste automaticky prováděli potřebné úlohy správy 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ý zabalí prostředek operačního systému, například popisovač souboru, popisovač okna nebo síťové připojení. Přestože systém uvolňování paměti dokáže sledovat životnost spravovaného objektu, který zapouzdřuje nespravovaný prostředek, nemá konkrétní znalosti o tom, jak prostředek vyčistit. Když vytvoříte objekt, který zapouzdřuje nespravovaný prostředek, doporučujeme zadat potřebný kód k vyčištění nespravovaného prostředku ve veřejné metodě Dispose . Poskytnutím metody Dispose povolíte uživatelům objektu explicitně uvolnit jeho paměť po dokončení objektu. Při použití objektu, který zapouzdřuje nespravovaný prostředek, byste měli být vědomi Dispose a podle potřeby ho volat. Další informace o čištění nespravovaných prostředků a příklad vzoru návrhu pro implementaci Dispose naleznete v tématu Uvolňování paměti.

Viz také