Garbagecollection en prestaties
In dit artikel worden problemen beschreven met betrekking tot garbagecollection en geheugengebruik. Hiermee worden problemen opgelost die betrekking hebben op de beheerde heap en wordt uitgelegd hoe u het effect van garbagecollection op uw toepassingen kunt minimaliseren. Elk probleem bevat koppelingen naar procedures die u kunt gebruiken om problemen te onderzoeken.
Hulpprogramma's voor prestatieanalyse
In de volgende secties worden de hulpprogramma's beschreven die beschikbaar zijn voor het onderzoeken van geheugengebruik en problemen met garbagecollection. De procedures die verderop in dit artikel worden beschreven, verwijzen naar deze hulpprogramma's.
Prestatiemeteritems voor geheugen
U kunt prestatiemeteritems gebruiken om prestatiegegevens te verzamelen. Zie Runtimeprofilering voor instructies. De .NET CLR-geheugencategorie prestatiemeteritems, zoals beschreven in Prestatiemeteritems in .NET, bevat informatie over de garbagecollector.
Foutopsporing met SOS
U kunt het Windows Debugger (WinDbg) gebruiken om objecten op de beheerde heap te inspecteren.
Als u WinDbg wilt installeren, installeert u Hulpprogramma's voor foutopsporing voor Windows via de pagina Hulpprogramma's voor foutopsporing downloaden.
ETW-gebeurtenissen garbagecollection
Gebeurtenistracering voor Windows (ETW) is een traceringssysteem dat een aanvulling vormt op de profilerings- en foutopsporingsondersteuning van .NET. Vanaf .NET Framework 4 bevatten ETW-gebeurtenissen voor garbagecollection nuttige informatie voor het analyseren van de beheerde heap vanuit een statistisch oogpunt. De gebeurtenis, die wordt gegenereerd wanneer een garbagecollection zich op het punt bevindt, bevat bijvoorbeeld GCStart_V1
de volgende informatie:
- Welke generatie objecten worden verzameld.
- Wat de garbagecollection heeft geactiveerd.
- Type garbagecollection (gelijktijdig of niet gelijktijdig).
ETW-gebeurtenislogboekregistratie is efficiënt en maskert geen prestatieproblemen met betrekking tot garbagecollection. Een proces kan eigen gebeurtenissen bieden in combinatie met ETW-gebeurtenissen. Bij het logboek kunnen zowel de gebeurtenissen van de toepassing als de garbagecollectiongebeurtenissen worden gecorreleerd om te bepalen hoe en wanneer er heap-problemen optreden. Een servertoepassing kan bijvoorbeeld gebeurtenissen aan het begin en einde van een clientaanvraag leveren.
De profilerings-API
De clr-profileringsinterfaces (Common Language Runtime) bieden gedetailleerde informatie over de objecten die zijn beïnvloed tijdens de garbagecollection. Een profiler kan worden gewaarschuwd wanneer een garbagecollection wordt gestart en eindigt. Het kan rapporten geven over de objecten op de beheerde heap, inclusief een identificatie van objecten in elke generatie. Zie Profileringsoverzicht voor meer informatie.
Profilers kunnen uitgebreide informatie bieden. Complexe profilers kunnen het gedrag van een toepassing echter mogelijk wijzigen.
Resourcebewaking van toepassingsdomein
Vanaf .NET Framework 4 kan ARM (Application Domain Resource Monitoring) hosts het CPU- en geheugengebruik per toepassingsdomein bewaken. Zie Toepassingsdomeinresourcebewaking voor meer informatie.
Prestatieproblemen oplossen
De eerste stap is om te bepalen of het probleem daadwerkelijk garbagecollection is. Als u vaststelt dat dit het is, selecteert u in de volgende lijst om het probleem op te lossen.
- Er wordt een uitzondering voor onvoldoende geheugen gegenereerd
- Het proces gebruikt te veel geheugen
- De garbagecollection maakt objecten niet snel genoeg vrij
- De beheerde heap is te gefragmenteerd
- Garbagecollection pauzes zijn te lang
- Generatie 0 is te groot
- CPU-gebruik tijdens een garbagecollection is te hoog
Probleem: Er wordt een uitzondering met onvoldoende geheugen gegenereerd
Er zijn twee legitieme gevallen voor een gegooid OutOfMemoryException :
Onvoldoende virtueel geheugen.
De garbagecollector wijst geheugen van het systeem toe in segmenten van een vooraf bepaalde grootte. Als voor een toewijzing een extra segment is vereist, maar er geen aaneengesloten vrije blok overblijft in de virtuele geheugenruimte van het proces, mislukt de toewijzing voor de beheerde heap.
Er is onvoldoende fysiek geheugen om toe te wijzen.
Prestatiecontroles |
---|
Bepaal of de uitzondering buiten het geheugen wordt beheerd. Bepaal hoeveel virtueel geheugen kan worden gereserveerd. Bepaal of er voldoende fysiek geheugen is. |
Als u vaststelt dat de uitzondering niet legitiem is, neemt u contact op met de microsoft-klantenservice en -ondersteuning met de volgende informatie:
- De stack met de beheerde uitzondering voor onvoldoende geheugen.
- Volledige geheugendump.
- Gegevens die aantonen dat het geen legitieme uitzondering voor onvoldoende geheugen is, inclusief gegevens die laten zien dat virtueel of fysiek geheugen geen probleem is.
Probleem: het proces gebruikt te veel geheugen
Een veelvoorkomende aanname is dat het geheugengebruik wordt weergegeven op het tabblad Prestaties van Windows Taakbeheer kan aangeven wanneer er te veel geheugen wordt gebruikt. Deze weergave heeft echter betrekking op de werkset; het biedt geen informatie over het gebruik van virtueel geheugen.
Als u vaststelt dat het probleem wordt veroorzaakt door de beheerde heap, moet u de beheerde heap in de loop van de tijd meten om patronen te bepalen.
Als u vaststelt dat het probleem niet wordt veroorzaakt door de beheerde heap, moet u systeemeigen foutopsporing gebruiken.
Probleem: De garbagecollection maakt objecten niet snel genoeg vrij
Wanneer het lijkt alsof objecten niet worden vrijgemaakt zoals verwacht voor garbagecollection, moet u bepalen of er sterke verwijzingen naar deze objecten zijn.
U kunt dit probleem ook tegenkomen als er geen garbagecollection is voor de generatie die een dood object bevat, wat aangeeft dat de finalizer voor het dode object niet is uitgevoerd. Dit is bijvoorbeeld mogelijk wanneer u een STA-toepassing (Single Threaded Apartment) uitvoert en de thread die de finalizer-wachtrij biedt, deze niet kan aanroepen.
Prestatiecontroles |
---|
Controleer verwijzingen naar objecten. Bepaal of er een finalizer is uitgevoerd. Bepaal of er objecten zijn die moeten worden voltooid. |
Probleem: de beheerde heap is te gefragmenteerd
Het fragmentatieniveau wordt berekend als de verhouding tussen vrije ruimte en het totale toegewezen geheugen voor de generatie. Voor generatie 2 is een acceptabel fragmentatieniveau niet meer dan 20%. Omdat generatie 2 erg groot kan worden, is de verhouding van fragmentatie belangrijker dan de absolute waarde.
Veel vrije ruimte in generatie 0 is geen probleem omdat dit de generatie is waar nieuwe objecten worden toegewezen.
Fragmentatie vindt altijd plaats in de grote object-heap omdat deze niet wordt gecomprimeerd. Vrije objecten die aangrenzend zijn, worden natuurlijk samengevouwen in één ruimte om te voldoen aan grote aanvragen voor objecttoewijzing.
Fragmentatie kan een probleem worden in generatie 1 en generatie 2. Als deze generaties een grote hoeveelheid vrije ruimte hebben na een garbagecollection, moet het objectgebruik van een toepassing mogelijk worden gewijzigd en moet u overwegen de levensduur van objecten op lange termijn opnieuw te evalueren.
Overmatige vastmaken van objecten kan fragmentatie verhogen. Als fragmentatie hoog is, kunnen er te veel objecten zijn vastgemaakt.
Als fragmentatie van het virtuele geheugen verhindert dat de garbagecollector segmenten toevoegt, kunnen de oorzaken een van de volgende oorzaken hebben:
Vaak laden en lossen van veel kleine assembly's.
Er zijn te veel verwijzingen naar COM-objecten bij het samenwerken met onbeheerde code.
Het maken van grote tijdelijke objecten, waardoor de grote object-heap vaak heap-segmenten toewijst en vrijkomt.
Bij het hosten van de CLR kan een toepassing aanvragen dat de garbagecollector de segmenten behoudt. Dit vermindert de frequentie van segmenttoewijzingen. Dit wordt bereikt met behulp van de vlag STARTUP_HOARD_GC_VM in de opsomming STARTUP_FLAGS.
Prestatiecontroles |
---|
Bepaal de hoeveelheid vrije ruimte in de beheerde heap. Het aantal vastgemaakte objecten bepalen. |
Als u denkt dat er geen legitieme oorzaak is voor de fragmentatie, neemt u contact op met de klantenservice en de ondersteuning van Microsoft.
Probleem: Garbagecollection pauzes zijn te lang
Garbagecollection werkt in zachte realtime, dus een toepassing moet enkele pauzes kunnen tolereren. Een criterium voor zachte realtime is dat 95% van de bewerkingen op tijd moet worden voltooid.
In gelijktijdige garbagecollection mogen beheerde threads worden uitgevoerd tijdens een verzameling, wat betekent dat pauzes zeer minimaal zijn.
Kortstondige garbageverzamelingen (generaties 0 en 1) duren slechts een paar milliseconden, dus het verlagen van pauzes is meestal niet haalbaar. U kunt de pauzes in verzamelingen van de tweede generatie echter verminderen door het patroon van toewijzingsaanvragen door een toepassing te wijzigen.
Een andere, nauwkeurigere methode is het gebruik van ETW-gebeurtenissen voor garbagecollection. U vindt de tijdsinstellingen voor verzamelingen door de tijdstempelverschillen voor een reeks gebeurtenissen toe te voegen. De hele verzamelingsreeks omvat schorsing van de uitvoeringsengine, de garbagecollection zelf en de hervatting van de uitvoeringsengine.
U kunt garbagecollectionmeldingen gebruiken om te bepalen of een server op het punt staat een verzameling van de tweede generatie te hebben en of het opnieuw omleiden van aanvragen naar een andere server kan eventuele problemen met pauzes vereenvoudigen.
Prestatiecontroles |
---|
Bepaal de tijdsduur in een garbagecollection. Bepaal wat een garbagecollection heeft veroorzaakt. |
Probleem: Generatie 0 is te groot
Generatie 0 heeft waarschijnlijk een groter aantal objecten op een 64-bits systeem, vooral wanneer u de garbagecollection van de server gebruikt in plaats van garbagecollection van werkstation. Dit komt doordat de drempelwaarde voor het activeren van een garbagecollection van de 0 generatie hoger is in deze omgevingen en verzamelingen van generatie 0 veel groter kunnen worden. De prestaties worden verbeterd wanneer een toepassing meer geheugen toewijst voordat een garbagecollection wordt geactiveerd.
Probleem: CPU-gebruik tijdens een garbagecollection is te hoog
HET CPU-gebruik is hoog tijdens een garbagecollection. Als een aanzienlijke hoeveelheid procestijd wordt besteed aan een garbagecollection, is het aantal verzamelingen te vaak of duurt de verzameling te lang. Een verhoogde toewijzingssnelheid van objecten op de beheerde heap zorgt ervoor dat garbagecollection vaker voorkomt. Als u de toewijzingssnelheid verlaagt, wordt de frequentie van garbagecollectionen verminderd.
U kunt toewijzingssnelheden bewaken met behulp van het Allocated Bytes/second
prestatiemeteritem. Zie Prestatiemeteritems in .NET voor meer informatie.
De duur van een verzameling is voornamelijk een factor van het aantal objecten dat na de toewijzing overleeft. De garbagecollector moet een grote hoeveelheid geheugen doorlopen als veel objecten moeten worden verzameld. Het werk om de overlevenden te comprimeren is tijdrovend. Als u wilt bepalen hoeveel objecten tijdens een verzameling zijn verwerkt, stelt u een onderbrekingspunt in het foutopsporingsprogramma aan het einde van een garbagecollection in voor een opgegeven generatie.
Prestatiecontroles |
---|
Bepaal of een hoog CPU-gebruik wordt veroorzaakt door garbagecollection. Stel een onderbrekingspunt in aan het einde van de garbagecollection. |
Richtlijnen voor probleemoplossing
In deze sectie worden richtlijnen beschreven waarmee u rekening moet houden wanneer u begint met uw onderzoeken.
Werkstation of server garbagecollection
Bepaal of u het juiste type garbagecollection gebruikt. Als uw toepassing meerdere threads en objectexemplaren gebruikt, gebruikt u de garbagecollection van de server in plaats van garbagecollection van werkstations. De garbagecollection van de server werkt op meerdere threads, terwijl de garbagecollection van het werkstation meerdere exemplaren van een toepassing nodig heeft om hun eigen threads voor garbagecollection uit te voeren en te concurreren voor CPU-tijd.
Een toepassing met een lage belasting en die taken niet vaak op de achtergrond uitvoert, zoals een service, kan werkstation garbagecollection gebruiken waarbij gelijktijdige garbagecollection is uitgeschakeld.
Wanneer moet u de grootte van de beheerde heap meten
Tenzij u een profiler gebruikt, moet u een consistent meetpatroon instellen om prestatieproblemen effectief te diagnosticeren. Houd rekening met de volgende punten om een planning op te stellen:
- Als u meet na een afvalverzameling van de tweede generatie, is de hele beheerde heap vrij van garbage (dode objecten).
- Als u onmiddellijk na een generatie 0 garbagecollection meet, worden de objecten in generaties 1 en 2 nog niet verzameld.
- Als u direct vóór een garbagecollection meet, meet u zoveel mogelijk toewijzing voordat de garbagecollection wordt gestart.
- Meten tijdens een garbagecollection is problematisch, omdat de gegevensstructuren van de garbagecollector niet geldig zijn voor doorkruising en u mogelijk niet de volledige resultaten kunnen geven. Dit is standaard.
- Wanneer u werkstation garbagecollection gebruikt met gelijktijdige garbagecollection, worden de vrijgemaakte objecten niet gecomprimeerd, zodat de heapgrootte hetzelfde of groter kan zijn (fragmentatie kan het lijken groter te zijn).
- Gelijktijdige garbagecollection op generatie 2 wordt vertraagd wanneer de belasting van het fysieke geheugen te hoog is.
In de volgende procedure wordt beschreven hoe u een onderbrekingspunt instelt, zodat u de beheerde heap kunt meten.
Een onderbrekingspunt instellen aan het einde van de garbagecollection
Voer in WinDbg met de sos-foutopsporingsprogramma-extensie geladen de volgende opdracht in:
bp mscorwks!WKS::GCHeap::RestartEE "j (dwo(mscorwks!WKS::GCHeap::GcCondemnedGeneration)==2) 'kb';'g'"
Ingesteld
GcCondemnedGeneration
op de gewenste generatie. Voor deze opdracht zijn persoonlijke symbolen vereist.Met deze opdracht wordt een onderbreking afgedwongen als
RestartEE
deze wordt uitgevoerd nadat de tweede generatie objecten zijn vrijgemaakt voor garbagecollection.In de garbagecollection van de server, slechts één thread aanroepen
RestartEE
, dus het onderbrekingspunt vindt slechts één keer plaats tijdens een garbagecollection van de tweede generatie.
Procedures voor prestatiecontrole
In deze sectie worden de volgende procedures beschreven om de oorzaak van uw prestatieprobleem te isoleren:
- Bepaal of het probleem wordt veroorzaakt door garbagecollection.
- Bepaal of de uitzondering buiten het geheugen wordt beheerd.
- Bepaal hoeveel virtueel geheugen kan worden gereserveerd.
- Bepaal of er voldoende fysiek geheugen is.
- Bepaal hoeveel geheugen de beheerde heap doorvoert.
- Bepaal hoeveel geheugen de beheerde heap reserveert.
- Bepaal grote objecten in generatie 2.
- Verwijzingen naar objecten bepalen.
- Bepaal of er een finalizer is uitgevoerd.
- Bepaal of er objecten zijn die moeten worden voltooid.
- Bepaal de hoeveelheid vrije ruimte in de beheerde heap.
- Het aantal vastgemaakte objecten bepalen.
- Bepaal de tijdsduur in een garbagecollection.
- Bepaal wat een garbagecollection heeft geactiveerd.
- Bepaal of een hoog CPU-gebruik wordt veroorzaakt door garbagecollection.
Bepalen of het probleem wordt veroorzaakt door garbagecollection
Bekijk de volgende twee prestatiemeteritems voor geheugen:
% tijd in GC. Geeft het percentage verstreken tijd weer dat is besteed aan het uitvoeren van een garbagecollection na de laatste garbagecollectioncyclus. Gebruik deze teller om te bepalen of de garbagecollector te veel tijd besteedt om beheerde heapruimte beschikbaar te maken. Als de tijd die is besteed aan garbagecollection relatief laag is, kan dit duiden op een resourceprobleem buiten de beheerde heap. Deze teller is mogelijk niet nauwkeurig wanneer gelijktijdige of achtergrond garbagecollection betrokken is.
# Totaal aantal doorgevoerde bytes. Geeft de hoeveelheid virtueel geheugen weer die momenteel is doorgevoerd door de garbagecollector. Gebruik deze teller om te bepalen of het geheugen dat door de garbagecollector wordt verbruikt, een overmatig deel is van het geheugen dat door uw toepassing wordt gebruikt.
De meeste prestatiemeteritems voor geheugen worden aan het einde van elke garbagecollection bijgewerkt. Daarom geven ze mogelijk niet de huidige voorwaarden weer waarover u informatie wilt.
Bepalen of de uitzondering buiten het geheugen wordt beheerd
Voer in het WinDbg- of Visual Studio-foutopsporingsprogramma met de sos-foutopsporingsextensie geladen de opdracht afdrukuitzondering (
pe
) in:!pe
Als de uitzondering wordt beheerd, OutOfMemoryException wordt deze weergegeven als het uitzonderingstype, zoals wordt weergegeven in het volgende voorbeeld.
Exception object: 39594518 Exception type: System.OutOfMemoryException Message: <none> InnerException: <none> StackTrace (generated):
Als de uitvoer geen uitzondering opgeeft, moet u bepalen van welke thread de uitzondering buiten het geheugen afkomstig is. Voer de volgende opdracht in het foutopsporingsprogramma in om alle threads met hun aanroepstacks weer te geven:
~\*kb
De thread met de stack met uitzonderingsoproepen wordt aangegeven door het
RaiseTheException
argument. Dit is het beheerde uitzonderingsobject.28adfb44 7923918f 5b61f2b4 00000000 5b61f2b4 mscorwks!RaiseTheException+0xa0
U kunt de volgende opdracht gebruiken om geneste uitzonderingen te dumpen.
!pe -nested
Als u geen uitzonderingen vindt, is de uitzondering buiten het geheugen afkomstig van niet-beheerde code.
Bepalen hoeveel virtueel geheugen kan worden gereserveerd
Voer in WinDbg met de SOS-foutopsporingsprogramma-extensie geladen de volgende opdracht in om de grootste gratis regio op te halen:
!address -summary
De grootste vrije regio wordt weergegeven zoals weergegeven in de volgende uitvoer.
Largest free region: Base 54000000 - Size 0003A980
In dit voorbeeld is de grootte van de grootste vrije regio ongeveer 24000 KB (3A980 in hexadecimaal). Deze regio is veel kleiner dan wat de garbagecollector nodig heeft voor een segment.
-Of-
Gebruik de
vmstat
opdracht:!vmstat
De grootste vrije regio is de grootste waarde in de kolom MAXIMUM, zoals wordt weergegeven in de volgende uitvoer.
TYPE MINIMUM MAXIMUM AVERAGE BLK COUNT TOTAL ~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~~~~ ~~~~ Free: Small 8K 64K 46K 36 1,671K Medium 80K 864K 349K 3 1,047K Large 1,384K 1,278,848K 151,834K 12 1,822,015K Summary 8K 1,278,848K 35,779K 51 1,824,735K
Bepalen of er voldoende fysiek geheugen is
Start Windows Taakbeheer.
Kijk op het
Performance
tabblad naar de vastgelegde waarde. (In Windows 7 bekijktCommit (KB)
u in deSystem group
.)Als de verbinding
Total
zich dicht bij hetLimit
bestand bevindt, hebt u weinig fysiek geheugen.
Bepalen hoeveel geheugen de beheerde heap doorvoert
Gebruik het
# Total committed bytes
prestatiemeteritem voor geheugen om het aantal bytes op te halen dat door de beheerde heap wordt doorgevoerd. De garbagecollector zet segmenten op een segment vast, niet allemaal tegelijk.Notitie
Gebruik de
# Bytes in all Heaps
prestatiemeteritem niet, omdat dit geen werkelijk geheugengebruik vertegenwoordigt door de beheerde heap. De grootte van een generatie wordt opgenomen in deze waarde en is in feite de drempelwaarde, dat wil gezegd, de grootte die een garbagecollection veroorzaakt als de generatie wordt gevuld met objecten. Daarom is deze waarde meestal nul.
Bepalen hoeveel geheugen de beheerde heap reserveert
Gebruik het
# Total reserved bytes
prestatiemeteritem voor geheugen.De garbagecollector reserveert geheugen in segmenten en u kunt bepalen waar een segment begint met behulp van de
eeheap
opdracht.Belangrijk
Hoewel u kunt bepalen hoeveel geheugen de garbagecollector toewijst voor elk segment, is segmentgrootte specifiek voor implementatie en kan deze op elk gewenst moment worden gewijzigd, ook in periodieke updates. Uw app mag nooit veronderstellingen maken over of afhankelijk zijn van een bepaalde segmentgrootte, en moet ook niet proberen om de hoeveelheid geheugen te configureren die beschikbaar is voor segmenttoewijzingen.
Voer in het WinDbg- of Visual Studio-foutopsporingsprogramma met de sos-foutopsporingsprogramma-extensie geladen de volgende opdracht in:
!eeheap -gc
Dit is het resultaat.
Number of GC Heaps: 2 ------------------------------ Heap 0 (002db550) generation 0 starts at 0x02abe29c generation 1 starts at 0x02abdd08 generation 2 starts at 0x02ab0038 ephemeral segment allocation context: none segment begin allocated size 02ab0000 02ab0038 02aceff4 0x0001efbc(126908) Large object heap starts at 0x0aab0038 segment begin allocated size 0aab0000 0aab0038 0aab2278 0x00002240(8768) Heap Size 0x211fc(135676) ------------------------------ Heap 1 (002dc958) generation 0 starts at 0x06ab1bd8 generation 1 starts at 0x06ab1bcc generation 2 starts at 0x06ab0038 ephemeral segment allocation context: none segment begin allocated size 06ab0000 06ab0038 06ab3be4 0x00003bac(15276) Large object heap starts at 0x0cab0038 segment begin allocated size 0cab0000 0cab0038 0cab0048 0x00000010(16) Heap Size 0x3bbc(15292) ------------------------------ GC Heap Size 0x24db8(150968)
De adressen die worden aangegeven door 'segment', zijn de beginadressen van de segmenten.
Grote objecten in generatie 2 bepalen
Voer in het WinDbg- of Visual Studio-foutopsporingsprogramma met de sos-foutopsporingsprogramma-extensie geladen de volgende opdracht in:
!dumpheap –stat
Als de beheerde heap groot is,
dumpheap
kan het even duren voordat deze klaar is.U kunt beginnen met analyseren vanaf de laatste regels van de uitvoer, omdat ze de objecten vermelden die de meeste ruimte gebruiken. Voorbeeld:
2c6108d4 173712 14591808 DevExpress.XtraGrid.Views.Grid.ViewInfo.GridCellInfo 00155f80 533 15216804 Free 7a747c78 791070 15821400 System.Collections.Specialized.ListDictionary+DictionaryNode 7a747bac 700930 19626040 System.Collections.Specialized.ListDictionary 2c64e36c 78644 20762016 DevExpress.XtraEditors.ViewInfo.TextEditViewInfo 79124228 121143 29064120 System.Object[] 035f0ee4 81626 35588936 Toolkit.TlkOrder 00fcae40 6193 44911636 WaveBasedStrategy.Tick_Snap[] 791242ec 40182 90664128 System.Collections.Hashtable+bucket[] 790fa3e0 3154024 137881448 System.String Total 8454945 objects
Het laatste object dat wordt vermeld, is een tekenreeks en neemt de meeste ruimte in beslag. U kunt uw toepassing onderzoeken om te zien hoe uw tekenreeksobjecten kunnen worden geoptimaliseerd. Als u tekenreeksen tussen 150 en 200 bytes wilt zien, voert u het volgende in:
!dumpheap -type System.String -min 150 -max 200
Een voorbeeld van de resultaten is als volgt.
Address MT Size Gen 1875d2c0 790fa3e0 152 2 System.String HighlightNullStyle_Blotter_PendingOrder-11_Blotter_PendingOrder-11 …
Het gebruik van een geheel getal in plaats van een tekenreeks voor een id kan efficiënter zijn. Als dezelfde tekenreeks duizenden keren wordt herhaald, kunt u overwegen om tekenreeksen te interneren. Zie het naslagonderwerp voor de String.Intern methode voor meer informatie over het interneren van tekenreeksen.
Verwijzingen naar objecten bepalen
Voer in WinDbg met de sos-foutopsporingsprogramma-extensie geladen de volgende opdracht in om verwijzingen naar objecten weer te geven:
!gcroot
-Of-
Als u de verwijzingen voor een specifiek object wilt bepalen, neemt u het adres op:
!gcroot 1c37b2ac
Wortels gevonden op stapels kunnen fout-positieven zijn. Gebruik de opdracht
!help gcroot
voor meer informatie.ebx:Root:19011c5c(System.Windows.Forms.Application+ThreadContext)-> 19010b78(DemoApp.FormDemoApp)-> 19011158(System.Windows.Forms.PropertyStore)-> … [omitted] 1c3745ec(System.Data.DataTable)-> 1c3747a8(System.Data.DataColumnCollection)-> 1c3747f8(System.Collections.Hashtable)-> 1c376590(System.Collections.Hashtable+bucket[])-> 1c376c98(System.Data.DataColumn)-> 1c37b270(System.Data.Common.DoubleStorage)-> 1c37b2ac(System.Double[]) Scan Thread 0 OSTHread 99c Scan Thread 6 OSTHread 484
Het kan lang duren voordat de
gcroot
opdracht is voltooid. Een object dat niet door garbagecollection wordt vrijgemaakt, is een live-object. Dit betekent dat een deel van de hoofdmap direct of indirect aan het object vasthoudt, dusgcroot
moet padinformatie naar het object worden geretourneerd. U moet de geretourneerde grafieken onderzoeken en zien waarom er nog steeds naar deze objecten wordt verwezen.
Bepalen of een finalizer is uitgevoerd
Voer een testprogramma uit dat de volgende code bevat:
GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect();
Als het probleem met de test wordt opgelost, betekent dit dat de garbagecollector geen objecten terugvorderde, omdat de finalizers voor die objecten waren onderbroken. Met GC.WaitForPendingFinalizers de methode kunnen de finalizers hun taken voltooien en het probleem oplossen.
Bepalen of er objecten zijn die moeten worden voltooid
Voer in het WinDbg- of Visual Studio-foutopsporingsprogramma met de sos-foutopsporingsprogramma-extensie geladen de volgende opdracht in:
!finalizequeue
Bekijk het aantal objecten dat gereed is voor voltooien. Als het getal hoog is, moet u onderzoeken waarom deze finalizers helemaal niet kunnen worden voortgezet of niet snel genoeg kunnen worden voortgezet.
Voer de volgende opdracht in om een uitvoer van threads op te halen:
!threads -special
Deze opdracht biedt uitvoer zoals de volgende.
OSID Special thread type 2 cd0 DbgHelper 3 c18 Finalizer 4 df0 GC SuspendEE
De finalizer-thread geeft aan welke finalizer, indien aanwezig, momenteel wordt uitgevoerd. Wanneer een finalizer-thread geen finalizers uitvoert, wacht deze op een gebeurtenis om aan te geven dat het werk moet worden uitgevoerd. Meestal ziet u de finalizer-thread in deze status, omdat deze wordt uitgevoerd op THREAD_HIGHEST_PRIORITY en moet worden voltooid met actieve finalizers, indien van toepassing, zeer snel.
De hoeveelheid vrije ruimte in de beheerde heap bepalen
Voer in het WinDbg- of Visual Studio-foutopsporingsprogramma met de sos-foutopsporingsprogramma-extensie geladen de volgende opdracht in:
!dumpheap -type Free -stat
Met deze opdracht wordt de totale grootte van alle vrije objecten op de beheerde heap weergegeven, zoals wordt weergegeven in het volgende voorbeeld.
total 230 objects Statistics: MT Count TotalSize Class Name 00152b18 230 40958584 Free Total 230 objects
Als u de vrije ruimte in generatie 0 wilt bepalen, voert u de volgende opdracht in voor informatie over geheugenverbruik per generatie:
!eeheap -gc
Met deze opdracht wordt uitvoer weergegeven die vergelijkbaar is met de volgende. De laatste regel toont het kortstondige segment.
Heap 0 (0015ad08) generation 0 starts at 0x49521f8c generation 1 starts at 0x494d7f64 generation 2 starts at 0x007f0038 ephemeral segment allocation context: none segment begin allocated size 00178250 7a80d84c 7a82f1cc 0x00021980(137600) 00161918 78c50e40 78c7056c 0x0001f72c(128812) 007f0000 007f0038 047eed28 0x03ffecf0(67103984) 3a120000 3a120038 3a3e84f8 0x002c84c0(2917568) 46120000 46120038 49e05d04 0x03ce5ccc(63855820)
Bereken de ruimte die wordt gebruikt door generatie 0:
? 49e05d04-0x49521f8c
Dit is het resultaat. Generatie 0 is ongeveer 9 MB.
Evaluate expression: 9321848 = 008e3d78
Met de volgende opdracht wordt de vrije ruimte binnen het bereik van de 0e generatie gedumpt:
!dumpheap -type Free -stat 0x49521f8c 49e05d04
Dit is het resultaat.
------------------------------ Heap 0 total 409 objects ------------------------------ Heap 1 total 0 objects ------------------------------ Heap 2 total 0 objects ------------------------------ Heap 3 total 0 objects ------------------------------ total 409 objects Statistics: MT Count TotalSize Class Name 0015a498 409 7296540 Free Total 409 objects
Deze uitvoer laat zien dat het 0e deel van de heap 9 MB ruimte voor objecten gebruikt en 7 MB vrij heeft. Deze analyse toont de mate waarin generatie 0 bijdraagt aan fragmentatie. Dit aantal heap-gebruiksrechten moet worden afgetrokken van het totale bedrag als de oorzaak van fragmentatie door objecten op lange termijn.
Het aantal vastgemaakte objecten bepalen
Voer in het WinDbg- of Visual Studio-foutopsporingsprogramma met de sos-foutopsporingsprogramma-extensie geladen de volgende opdracht in:
!gchandles
De weergegeven statistieken bevatten het aantal vastgemaakte ingangen, zoals in het volgende voorbeeld wordt weergegeven.
GC Handle Statistics: Strong Handles: 29 Pinned Handles: 10
De tijdsduur in een garbagecollection bepalen
Controleer het prestatiemeteritem van het
% Time in GC
geheugen.De waarde wordt berekend met behulp van een voorbeeldintervaltijd. Omdat de tellers aan het einde van elke garbagecollection worden bijgewerkt, heeft het huidige voorbeeld dezelfde waarde als het vorige voorbeeld als er geen verzamelingen zijn opgetreden tijdens het interval.
Verzamelingstijd wordt verkregen door de intervaltijd van de steekproef te vermenigvuldigen met de percentagewaarde.
De volgende gegevens bevatten vier steekproefintervallen van twee seconden, voor een onderzoek van 8 seconden. In
Gen0
de kolommen ,Gen1
enGen2
kolommen wordt het totale aantal garbagecollection's weergegeven dat aan het einde van het interval voor die generatie is voltooid.Interval Gen0 Gen1 Gen2 % Time in GC 1 9 3 1 10 2 10 3 1 1 3 11 3 1 3 4 11 3 1 3
Deze informatie wordt niet weergegeven wanneer de garbagecollection is opgetreden, maar u kunt het aantal garbagecollection's bepalen dat in een interval van tijd is opgetreden. Uitgaande van het ergste geval is de tiende generatie 0 garbagecollection voltooid aan het begin van het tweede interval en de elfde generatie 0 garbagecollection voltooid aan het einde van het derde interval. De tijd tussen het einde van de tiende en het einde van de elfde garbagecollection is ongeveer 2 seconden en de prestatiemeteritem toont 3%, dus de duur van de elfde generatie 0 garbagecollection was (2 seconden * 3% = 60 ms).
In het volgende voorbeeld zijn er vijf intervallen.
Interval Gen0 Gen1 Gen2 % Time in GC 1 9 3 1 3 2 10 3 1 1 3 11 4 1 1 4 11 4 1 1 5 11 4 2 20
De tweede generatie 2 garbagecollection is gestart tijdens het vierde interval en voltooid met het vijfde interval. Uitgaande van het ergste geval was de laatste garbagecollection voor een verzameling van de 0 generatie die aan het begin van het derde interval is voltooid en de garbagecollection van de tweede generatie is voltooid aan het einde van het vijfde interval. Daarom is de tijd tussen het einde van de generatie 0 garbagecollection en het einde van de 2e generatie garbagecollection 4 seconden. Omdat de
% Time in GC
teller 20% is, is de maximale hoeveelheid tijd die de generatie 2 garbagecollection kan hebben genomen (4 seconden * 20% = 800 ms).U kunt ook de lengte van een garbagecollection bepalen met behulp van ETW-gebeurtenissen voor garbagecollection en de informatie analyseren om de duur van de garbagecollection te bepalen.
De volgende gegevens bevatten bijvoorbeeld een gebeurtenisreeks die is opgetreden tijdens een niet-gelijktijdige garbagecollection.
Timestamp Event name 513052 GCSuspendEEBegin_V1 513078 GCSuspendEEEnd 513090 GCStart_V1 517890 GCEnd_V1 517894 GCHeapStats 517897 GCRestartEEBegin 517918 GCRestartEEEnd
Het onderbreken van de beheerde thread duurde 26us (
GCSuspendEEEnd
–GCSuspendEEBegin_V1
).De daadwerkelijke garbagecollection duurde 4,8 ms (
GCEnd_V1
–GCStart_V1
).Het hervatten van de beheerde threads duurde 21us (
GCRestartEEEnd
–GCRestartEEBegin
).De volgende uitvoer bevat een voorbeeld voor garbagecollection op de achtergrond en bevat de proces-, thread- en gebeurtenisvelden. (Niet alle gegevens worden weergegeven.)
timestamp(us) event name process thread event field 42504385 GCSuspendEEBegin_V1 Test.exe 4372 1 42504648 GCSuspendEEEnd Test.exe 4372 42504816 GCStart_V1 Test.exe 4372 102019 42504907 GCStart_V1 Test.exe 4372 102020 42514170 GCEnd_V1 Test.exe 4372 42514204 GCHeapStats Test.exe 4372 102020 42832052 GCRestartEEBegin Test.exe 4372 42832136 GCRestartEEEnd Test.exe 4372 63685394 GCSuspendEEBegin_V1 Test.exe 4744 6 63686347 GCSuspendEEEnd Test.exe 4744 63784294 GCRestartEEBegin Test.exe 4744 63784407 GCRestartEEEnd Test.exe 4744 89931423 GCEnd_V1 Test.exe 4372 102019 89931464 GCHeapStats Test.exe 4372
De
GCStart_V1
gebeurtenis op 42504816 geeft aan dat dit een achtergrond garbagecollection is, omdat het laatste veld is1
. Dit wordt garbagecollection Nr. 102019.De
GCStart
gebeurtenis treedt op omdat er behoefte is aan een tijdelijke garbagecollection voordat u een achtergrond garbagecollection start. Dit wordt garbagecollection nr. 102020.Op 42514170 is garbagecollection nr. 102020 voltooid. De beheerde threads worden op dit moment opnieuw gestart. Dit is voltooid op thread 4372, waardoor deze achtergrond garbagecollection werd geactiveerd.
Op draad 4744 treedt een ophanging op. Dit is het enige moment waarop de achtergrond garbagecollection beheerde threads moet onderbreken. Deze duur is ongeveer 99 ms ((63784407-63685394)/1000).
De
GCEnd
gebeurtenis voor de achtergrond garbagecollection bevindt zich op 89931423. Dit betekent dat de achtergrond garbagecollection ongeveer 47seconds ((89931423-42504816)/1000 duurde.Terwijl de beheerde threads worden uitgevoerd, kunt u zien dat er een willekeurig aantal tijdelijke garbagecollection's optreedt.
Bepalen wat een garbagecollection heeft geactiveerd
Voer in het WinDbg- of Visual Studio-foutopsporingsprogramma met de sos-foutopsporingsprogramma-extensie geladen de volgende opdracht in om alle threads met hun aanroepstacks weer te geven:
~*Kb
Met deze opdracht wordt uitvoer weergegeven die vergelijkbaar is met de volgende.
0012f3b0 79ff0bf8 mscorwks!WKS::GCHeap::GarbageCollect 0012f454 30002894 mscorwks!GCInterface::CollectGeneration+0xa4 0012f490 79fa22bd fragment_ni!request.Main(System.String[])+0x48
Als de garbagecollection is veroorzaakt door een melding van weinig geheugen van het besturingssysteem, is de aanroepstack vergelijkbaar, behalve dat de thread de finalizer-thread is. De finalizer-thread krijgt een asynchrone melding over weinig geheugen en veroorzaakt de garbagecollection.
Als de garbagecollection is veroorzaakt door geheugentoewijzing, wordt de stack als volgt weergegeven:
0012f230 7a07c551 mscorwks!WKS::GCHeap::GarbageCollectGeneration 0012f2b8 7a07cba8 mscorwks!WKS::gc_heap::try_allocate_more_space+0x1a1 0012f2d4 7a07cefb mscorwks!WKS::gc_heap::allocate_more_space+0x18 0012f2f4 7a02a51b mscorwks!WKS::GCHeap::Alloc+0x4b 0012f310 7a02ae4c mscorwks!Alloc+0x60 0012f364 7a030e46 mscorwks!FastAllocatePrimitiveArray+0xbd 0012f424 300027f4 mscorwks!JIT_NewArr1+0x148 000af70f 3000299f fragment_ni!request..ctor(Int32, Single)+0x20c 0000002a 79fa22bd fragment_ni!request.Main(System.String[])+0x153
Een Just-In-Time-helper (
JIT_New*
) beltGCHeap::GarbageCollectGeneration
uiteindelijk . Als u bepaalt dat de garbagecollection van de tweede generatie wordt veroorzaakt door toewijzingen, moet u bepalen welke objecten worden verzameld door een garbagecollection van de tweede generatie en hoe u deze kunt vermijden. Dat wil gezegd, u wilt het verschil bepalen tussen het begin en het einde van een garbagecollection van de tweede generatie, en de objecten die de verzameling van de tweede generatie hebben veroorzaakt.Voer bijvoorbeeld de volgende opdracht in het foutopsporingsprogramma in om het begin van een verzameling van de tweede generatie weer te geven:
!dumpheap –stat
Voorbeelduitvoer (ingekort om de objecten weer te geven die de meeste ruimte gebruiken):
79124228 31857 9862328 System.Object[] 035f0384 25668 11601936 Toolkit.TlkPosition 00155f80 21248 12256296 Free 79103b6c 297003 13068132 System.Threading.ReaderWriterLock 7a747ad4 708732 14174640 System.Collections.Specialized.HybridDictionary 7a747c78 786498 15729960 System.Collections.Specialized.ListDictionary+DictionaryNode 7a747bac 700298 19608344 System.Collections.Specialized.ListDictionary 035f0ee4 89192 38887712 Toolkit.TlkOrder 00fcae40 6193 44911636 WaveBasedStrategy.Tick_Snap[] 7912c444 91616 71887080 System.Double[] 791242ec 32451 82462728 System.Collections.Hashtable+bucket[] 790fa3e0 2459154 112128436 System.String Total 6471774 objects
Herhaal de opdracht aan het einde van generatie 2:
!dumpheap –stat
Voorbeelduitvoer (ingekort om de objecten weer te geven die de meeste ruimte gebruiken):
79124228 26648 9314256 System.Object[] 035f0384 25668 11601936 Toolkit.TlkPosition 79103b6c 296770 13057880 System.Threading.ReaderWriterLock 7a747ad4 708730 14174600 System.Collections.Specialized.HybridDictionary 7a747c78 786497 15729940 System.Collections.Specialized.ListDictionary+DictionaryNode 7a747bac 700298 19608344 System.Collections.Specialized.ListDictionary 00155f80 13806 34007212 Free 035f0ee4 89187 38885532 Toolkit.TlkOrder 00fcae40 6193 44911636 WaveBasedStrategy.Tick_Snap[] 791242ec 32370 82359768 System.Collections.Hashtable+bucket[] 790fa3e0 2440020 111341808 System.String Total 6417525 objects
De
double[]
objecten zijn verdwenen vanaf het einde van de uitvoer, wat betekent dat ze zijn verzameld. Deze objecten zijn ongeveer 70 MB. De resterende objecten zijn niet veel veranderd. Daarom waren dezedouble[]
objecten de reden waarom deze generatie 2 garbagecollection plaatsvond. De volgende stap is om te bepalen waarom dedouble[]
objecten er zijn en waarom ze zijn gestorven. U kunt de codeontwikkelaar vragen waar deze objecten vandaan komen of u kunt degcroot
opdracht gebruiken.
Bepalen of een hoog CPU-gebruik wordt veroorzaakt door garbagecollection
Correleert de prestatiemeteritemwaarde van het
% Time in GC
geheugen met de procestijd.Als de
% Time in GC
waarde op hetzelfde moment als procestijd piekt, veroorzaakt garbagecollection een hoog CPU-gebruik. Anders kunt u de toepassing profileren om te bepalen waar het hoge gebruik plaatsvindt.