Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Automatisch geheugenbeheer is een van de services die de Common Language Runtime biedt tijdens beheerde uitvoering. De garbagecollector van Common Language Runtime beheert de toewijzing en het vrijlaten van geheugen voor een toepassing. Voor ontwikkelaars betekent dit dat u geen code hoeft te schrijven om geheugenbeheertaken uit te voeren wanneer u beheerde toepassingen ontwikkelt. Automatisch geheugenbeheer kan veelvoorkomende problemen voorkomen, zoals vergeten een object vrij te maken en een geheugenlek te veroorzaken of toegang te krijgen tot geheugen voor een object dat al is vrijgemaakt. In deze sectie wordt beschreven hoe de garbagecollector geheugen toewijst en vrijgeeft.
Geheugen toewijzen
Wanneer u een nieuw proces initialiseert, behoudt de runtime een aaneengesloten regio met adresruimte voor het proces. Deze gereserveerde adresruimte wordt de beheerde heap genoemd. De beheerde heap onderhoudt een aanwijzer naar het adres waar het volgende object in de heap wordt toegewezen. In eerste instantie wordt deze aanwijzer ingesteld op het basisadres van de beheerde heap. Alle referentietypen worden toegewezen aan de beheerde heap. Wanneer een toepassing het eerste referentietype maakt, wordt geheugen toegewezen voor het type op het basisadres van de beheerde heap. Wanneer de toepassing het volgende object maakt, wijst de afvalverzamelaar geheugen toe in de adresruimte direct volgend op het eerste object. Zolang er adresruimte beschikbaar is, blijft de garbagecollector op deze manier ruimte toewijzen voor nieuwe objecten.
Het toewijzen van geheugen van de beheerde heap is sneller dan de toewijzing van niet-beheerde geheugen. Omdat de runtime geheugen toewijst aan een object door een waarde toe te voegen aan een aanwijzer, is het bijna net zo snel als het toewijzen van geheugen van de stack. Bovendien, omdat nieuwe objecten die opeenvolgend worden toegewezen, aaneengesloten worden opgeslagen in de beheerde heap, heeft een toepassing zeer snel toegang tot de objecten.
Geheugen vrijgeven
De optimalisatie-engine van de garbagecollector bepaalt de beste tijd om een verzameling uit te voeren op basis van de toewijzingen die worden gemaakt. Wanneer de garbagecollector een verzameling uitvoert, wordt het geheugen vrijgegeven voor objecten die niet meer door de toepassing worden gebruikt. Hiermee wordt bepaald welke objecten niet meer worden gebruikt door de wortels van de toepassing te onderzoeken. Elke toepassing heeft een set wortels. Elke root verwijst naar een object in de beheerde heap of is ingesteld op null. De wortels van een toepassing omvatten statische velden, lokale variabelen en parameters op de stack van een thread, evenals CPU-registers. De garbagecollector heeft toegang tot de lijst met actieve roots die de Just-In-Time-compiler (JIT) en de runtime onderhouden. Met behulp van deze lijst wordt de wortels van een toepassing onderzocht en in het proces wordt een grafiek gemaakt die alle objecten bevat die bereikbaar zijn vanuit de wortels.
Objecten die zich niet in de grafiek bevinden, zijn niet bereikbaar vanuit de wortels van de toepassing. De geheugenbeheerder beschouwt onbereikbare objecten als afval en zal het toegewezen geheugen ervoor vrijmaken. Tijdens een inzamelingsbeurt onderzoekt de vuilnisverzamelaar de beheerde heap, op zoek naar de blokken adresruimte die worden bezet door onbereikbare objecten. Terwijl elk onbereikbaar object wordt gedetecteerd, gebruikt het een functie voor het kopiëren van geheugen om de bereikbare objecten in het geheugen te comprimeren, waardoor de blokken adresruimten worden vrijgemaakt die zijn toegewezen aan onbereikbare objecten. Zodra het geheugen voor de bereikbare objecten is gecomprimeerd, plaatst de garbagecollector de benodigde aanwijzercorrecties zodat de wortels van de toepassing verwijzen naar de objecten op hun nieuwe locaties. Ook wordt de aanwijzer van de beheerde heap na het laatst bereikbaar object geplaatst. Houd er rekening mee dat het geheugen alleen wordt gecomprimeerd als een verzameling een aanzienlijk aantal onbereikbare objecten detecteert. Indien alle objecten in de beheerde heap een verzameling overleven, is er geen geheugencompactie nodig.
Ter verbetering van de prestaties wijst de runtime geheugen toe voor grote objecten in een afzonderlijke heap. De garbagecollector geeft automatisch het geheugen vrij voor grote objecten. Om echter te voorkomen dat grote objecten in het geheugen worden verplaatst, wordt dit geheugen niet gecomprimeerd.
Generaties en prestaties
Om de prestaties van de garbagecollector te optimaliseren, is de beheerde heap onderverdeeld in drie generaties: 0, 1 en 2. Het geheugenbeheer-algoritme van de runtime is gebaseerd op verschillende generalisaties die de computersoftware-industrie heeft ontdekt door te experimenteren met geheugenbeheerstrategieën. Ten eerste is het sneller om het geheugen te comprimeren voor een deel van de beheerde heap dan voor de hele beheerde heap. Ten tweede hebben nieuwere objecten kortere levensduur en hebben oudere objecten langere levensduur. Ten slotte zijn nieuwere objecten meestal gerelateerd aan elkaar en worden ze rond dezelfde tijd door de toepassing geopend.
De garbagecollector van de runtime slaat nieuwe objecten op in generatie 0. Objecten die vroeg in de levensduur van de toepassing zijn gemaakt en de verzamelingen overleven, worden gepromoveerd en opgeslagen in generaties 1 en 2. Het proces van objectpromotie wordt verderop in dit onderwerp beschreven. Omdat het sneller is om een deel van de beheerde heap te comprimeren dan de hele heap, stelt deze aanpak de garbage collector in staat het geheugen in een specifieke generatie vrij te geven, in plaats van het geheugen voor de hele beheerde heap vrij te geven telkens wanneer er een verzameling wordt uitgevoerd.
In werkelijkheid voert de garbagecollector een verzameling uit wanneer generatie 0 vol is. Als een toepassing probeert een nieuw object te maken wanneer generatie 0 vol is, detecteert de garbagecollector dat er geen adresruimte overblijft in generatie 0 om toe te wijzen voor het object. De garbagecollector voert een verzameling uit in een poging om de adresruimte in generatie 0 voor het object vrij te maken. De vuilnisverzamelaar begint met het onderzoeken van de objecten in generatie 0 in plaats van alle objecten in de beheerde rommelhoop. Dit is de meest efficiënte benadering, omdat nieuwe objecten meestal korte levensduur hebben en het wordt verwacht dat veel van de objecten in generatie 0 niet meer worden gebruikt door de toepassing wanneer een verzameling wordt uitgevoerd. Bovendien maakt een verzameling van generatie 0 vaak voldoende geheugen vrij, zodat de toepassing nieuwe objecten kan blijven maken.
Nadat de garbagecollector een verzameling van generatie 0 heeft uitgevoerd, wordt het geheugen voor de bereikbare objecten gecomprimeerd, zoals eerder in dit onderwerp wordt uitgelegd in Geheugen vrijgeven . De vuilnisopruimer promoveert vervolgens deze objecten en beschouwt dit deel van de beheerde heap als generatie 1. Omdat objecten die verzamelingen overleven, langere levensduur hebben, is het zinvol om ze naar een hogere generatie te promoveren. Als gevolg hiervan hoeft de garbagecollector de objecten in generaties 1 en 2 niet telkens opnieuw te herbeleven wanneer deze een verzameling van generatie 0 uitvoert.
Nadat de garbagecollector zijn eerste verzameling van generatie 0 uitvoert en de bereikbare objecten naar generatie 1 heeft gepromoot, wordt de rest van de beheerde heap als generatie 0 beschouwd. Het blijft geheugen toewijzen voor nieuwe objecten van generatie 0 totdat generatie 0 vol is en het is nodig om een andere verzameling uit te voeren. Op dit moment bepaalt de optimalisatiemotor van de garbage collector of het noodzakelijk is om de objecten in oudere generaties te onderzoeken. Als een verzameling van generatie 0 bijvoorbeeld onvoldoende geheugen vrijgeeft voor de toepassing om de poging tot het maken van een nieuw object te voltooien, kan de garbagecollector een verzameling van generatie 1 en vervolgens generatie 2 uitvoeren. Als dit onvoldoende geheugen vrijgeeft, kan de vuilopruiming generaties 2, 1 en 0 verzamelen. Na elke verzameling compacteert de vuilnisophaler de bereikbare objecten van generatie 0 en promoveert ze naar generatie 1. Objecten in generatie 1 die verzamelingen overleven, worden gepromoveerd tot generatie 2. Omdat de garbagecollector slechts drie generaties ondersteunt, blijven objecten in generatie 2 die een inzamelingsproces overleven in generatie 2 totdat ze tijdens een toekomstige inzameling onbereikbaar worden verklaard.
Geheugen vrijgeven voor niet-beheerde resources
Voor het merendeel van de objecten die door uw toepassing worden gemaakt, kunt u vertrouwen op de garbagecollector om automatisch de benodigde geheugenbeheertaken uit te voeren. Niet-beheerde resources vereisen echter een expliciete handeling voor opruimen. Het meest voorkomende type onbeheerde resource is een object dat een besturingssysteemresource verpakt, zoals een bestandsgreep, venstergreep of netwerkverbinding. Hoewel de garbagecollector de levensduur van een beheerd object kan bijhouden dat een niet-beheerde resource inkapselt, heeft deze geen specifieke kennis over het opschonen van de resource. Wanneer u een object maakt dat een niet-beheerde resource inkapselt, wordt u aangeraden de benodigde code op te geven voor het opschonen van de onbeheerde resource in een openbare verwijderingsmethode. Door een verwijderingsmethode op te geven, stelt u gebruikers van uw object in staat om het geheugen expliciet vrij te maken wanneer ze klaar zijn met het object. Wanneer u een object gebruikt dat een niet-beheerde resource inkapselt, moet u rekening houden met Verwijderen en indien nodig aanroepen. Zie Garbagecollection voor meer informatie over het opschonen van onbeheerde resources en een voorbeeld van een ontwerppatroon voor het implementeren van Verwijdering.