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.
Automatická správa paměti je jednou ze služeb, které modul CLR (Common Language Runtime) poskytuje během spravovaného spouštění. Správce paměti modulu CLR (Common Language Runtime) spravuje přidělování a uvolňová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 garbage collector alokuje a uvolňuje 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, garbage collector pro něj přidělí paměť v adresním prostoru bezprostředně za prvním objektem. Pokud je adresní prostor k dispozici, správce 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ž přidělení nespravované paměti. Vzhledem k tomu, že běhové prostředí přiděluje paměť pro objekt přidáním hodnoty k ukazateli, je to téměř stejně rychlé jako přidělování 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řenů. 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. Garbage collector má přístup k seznamu aktivních kořenů, které kompilátor JIT (just-in-time) a runtime udržuje. Pomocí tohoto seznamu prozkoumá kořeny aplikace a při tom vytvoří graf, který obsahuje všechny objekty, jež jsou dosažitelné z těchto kořenů.
Objekty, které nejsou v grafu, jsou nedostupné z kořenového adresáře aplikace. Automatický správce paměti považuje nedostupné objekty za odpad a uvolní paměť, která jim byla přidělena. 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.
Správce 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ž celou haldu, umožňuje toto schéma uvolňování paměti v konkrétní generaci, místo uvolňování paměti pro celou spravovanou haldu při každé 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á, garbage collector zjistí, že v generaci 0 již nezbývá žádný adresní prostor, který by se pro objekt přidělil. Správce paměti provádí kolekci ve snaze uvolnit adresní prostor v generaci 0 pro objekt. 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 povyšuje a považuje tuto část haldy spravované paměti za generaci 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 garbage collector nemusí znovu zkoumat objekty v generacích 1 a 2 pokaždé, když provádí kolekci v generaci 0.
Jakmile systém uvolňování paměti provede první kolekci generace 0 a povýší dosažitelné objekty na generaci 1, považuje zbytek spravované haldy za generaci 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 správce paměti určuje, zda je nutné prozkoumat objekty ve starších generacích. Pokud například kolekce generace 0 nezíská dostatek paměti, aby aplikace úspěšně dokončila svůj pokus o vytvoření nového objektu, uvolňovač paměti může provést kolekci generace 1 a následně 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 zkompaktuje dosažitelné objekty v generaci 0 a přesune je do generace 1. Objekty v generaci 1, které přežijí kolekce, jsou povýšeny na generaci 2. Vzhledem k tomu, že garbage collector podporuje pouze tři generace, objekty, které projdou sběrem v generaci 2, tam zůstanou, dokud nebudou při příštím sběru označeny jako nedosažitelné.
Uvolnění paměti pro nespravované prostředky
U většiny objektů, které vaše aplikace vytvoří, se můžete spolehnout na garbage collector, který automaticky provede 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í. I když garbage collector dokáže sledovat životnost spravovaného objektu, který zapouzdřuje nespravovaný prostředek, nemá specifické 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.