Uvolnění paměti a výkon
Toto téma popisuje problémy související s uvolňováním paměti a využitím paměti. Řeší problémy související se spravovanou haldou a vysvětluje, jak minimalizovat účinek uvolňování paměti na aplikace. Každý problém obsahuje odkazy na postupy, které můžete použít ke zkoumání problémů.
Nástroje pro analýzu výkonu
Následující části popisují nástroje, které jsou k dispozici pro zkoumání využití paměti a problémů s uvolňováním paměti. Postupy uvedené dále v tomto tématu se vztahují k těmto nástrojům.
Čítače výkonu paměti
Čítače výkonu můžete použít ke shromažďování dat o výkonu. Pokyny najdete v tématu Profilace modulu runtime. Kategorie paměti .NET CLR čítačů výkonu, jak je popsáno v tématu Čítače výkonu v rozhraní .NET, poskytuje informace o systému uvolňování paměti.
Ladění pomocí SOS
Ke kontrole objektů na spravované haldě můžete použít Windows Debugger (WinDbg).
Pokud chcete nainstalovat WinDbg, nainstalujte ladicí nástroje pro Windows na stránce Stáhnout ladicí nástroje pro Windows nástroje.
Události Trasování událostí pro Windows uvolnění paměti
Trasování událostí pro Windows (ETW) je systém trasování, který doplňuje podporu profilace a ladění, kterou poskytuje .NET. Počínaje .NET Framework 4 zachycují události Trasování událostí pro Windows pro uvolňování paměti užitečné informace pro analýzu spravované haldy ze statistického hlediska. Například událost, která je vyvolána, když dojde k uvolňování GCStart_V1 paměti, poskytuje následující informace:
Která generace objektů se shromažďuje.
Co aktivoval uvolňování paměti.
Typ uvolňování paměti (souběžné nebo ne souběžné)
Protokolování událostí trasování událostí pro Windows je efektivní a nezamaskuje žádné problémy s výkonem související s uvolňováním paměti. Proces může poskytovat vlastní události ve spojení s událostmi Trasování událostí pro Windows. Při zaprotokolování je možné korelovat události aplikace i události uvolňování paměti, aby bylo možné určit, jak a kdy dojde k problémům s haldou. Serverová aplikace může například poskytovat události na začátku a konci požadavku klienta.
Rozhraní API pro profilaci
Rozhraní profilace modulu CLR (Common Language Runtime) poskytují podrobné informace o objektech, které byly ovlivněny během uvolňování paměti. Profiler může být upozorněn při spuštění a ukončení uvolňování paměti. Může poskytovat sestavy o objektech ve spravované haldě, včetně identifikace objektů v každé generaci. Další informace najdete v tématu Přehled profilace.
Profilátory mohou poskytovat komplexní informace. Složité profilátory ale mohou potenciálně upravovat chování aplikace.
Sledování prostředků domény aplikace
Počínaje .NET Framework 4 umožňuje monitorování prostředků domény aplikace (ARM) hostitelům monitorovat využití procesoru a paměti podle domény aplikace. Další informace najdete v tématu Monitorování prostředků domény aplikace.
Řešení potíží s výkonem
Prvním krokem je určení, jestli je problém ve skutečnosti uvolňování paměti. Pokud zjistíte, že je, vyberte z následujícího seznamu a problém vyřešte.
Problém: Vyvolá se výjimka, která je mimo paměť.
Existují dva legitimní případy, kdy je možné spravovaný OutOfMemoryException objekt vyvolat:
Došla vám virtuální paměť.
Systém uvolňování paměti přiděluje paměť systému v segmentech předem určené velikosti. Pokud přidělení vyžaduje další segment, ale ve virtuálním paměťovém prostoru procesu nezůzí žádný souvislé volné bloky, přidělení pro spravovanou haldu selže.
Nemá dostatek fyzické paměti pro přidělení.
| Kontroly výkonu |
|---|
| Zjistěte, jestli je výjimka mimo paměť spravovaná. Určete, kolik virtuální paměti je možné rezervovat. Zjistěte, jestli je k dispozici dostatek fyzické paměti. |
Pokud zjistíte, že výjimka není legitimní, obraťte se na oddělení služeb zákazníkům a podpoře Microsoftu s následujícími informacemi:
Zásobník s výjimkou spravovaného stavu mimo paměť.
Úplný výpis paměti.
Data, která prokazují, že se jedná o legitimní výjimku mimo paměť, včetně dat, která ukazují, že virtuální nebo fyzická paměť není problém.
Problém: Proces používá příliš mnoho paměti.
Běžným předpokladem je, že zobrazení využití paměti na kartě Výkon Windows Správce úloh může značit, kdy se používá příliš mnoho paměti. Toto zobrazení se však týká pracovní sady. neposkytuje informace o využití virtuální paměti.
Pokud zjistíte, že příčinou problému je spravovaná halda, musíte změřit spravovanou haldu v průběhu času, abyste zjistili případné vzory.
Pokud zjistíte, že problém není způsobený spravovanou haldou, musíte použít nativní ladění.
Problém: Systém uvolňování paměti neuvolňuje objekty dostatečně rychle.
Pokud se zdá, že objekty nejsou uvolněny podle očekávání pro uvolňování paměti, musíte určit, zda existují nějaké silné odkazy na tyto objekty.
K tomuto problému může dojít také v případě, že pro generaci, která obsahuje neuměný objekt, nebyl uvolněn žádný systém uvolňování paměti, což značí, že finalizační metoda pro nespouštěný objekt nebyla spuštěna. To je možné například v případě, že používáte aplikaci sta (single-threaded) a vlákno, které frontu finalizační metody poskytuje, do ní nemůže volat.
| Kontroly výkonu |
|---|
| Zkontrolujte odkazy na objekty. Zjistěte, jestli byla spuštěna finalizační metoda. Určete, zda existují objekty čekající na dokončení. |
Problém: Spravovaná halda je příliš fragmentovaná
Úroveň fragmentace se vypočítá jako poměr volného místa nad celkovou přidělenou pamětí pro generaci. U 2. generace není přijatelná úroveň fragmentace větší než 20 %. Vzhledem k tomu, že generace 2 může být velmi velká, je poměr fragmentace důležitější než absolutní hodnota.
Velké množství volného místa v generaci 0 není problém, protože se jedná o generaci, ve které se přidělují nové objekty.
Fragmentace se vždy vyskytuje ve velké haldě objektů, protože není komprimovaná. Volné objekty, které sousedí, jsou přirozeně sbalené do jednoho prostoru, aby splňovaly požadavky na přidělení velkých objektů.
Fragmentace se může stát problémem ve 1. a 2. generaci. Pokud mají tyto generace po uvolnění paměti velké množství volného místa, může použití objektů aplikace potřebovat úpravy a měli byste zvážit opětovné vyhodnocení životnosti dlouhodobých objektů.
Nadměrné připnutí objektů může zvýšit fragmentaci. Pokud je fragmentace vysoká, mohlo se připnout příliš mnoho objektů.
Pokud fragmentace virtuální paměti brání systému uvolňování paměti v přidávání segmentů, může to mít jednu z následujících příčin:
Časté načítání a uvolňování mnoha malých sestavení.
Při vzájemné spolupráci s nespravovaným kódem podržíte příliš mnoho odkazů na objekty COM.
Vytváření velkých přechodných objektů, což způsobuje, že velká halda objektů často přiděluje a volné segmenty haldy.
Při hostování modulu CLR může aplikace požádat, aby systém uvolňování paměti zachoval své segmenty. Tím se snižuje frekvence přidělování segmentů. Toho lze dosáhnout pomocí příznaku STARTUP_HOARD_GC_VM ve výčtu STARTUP_FLAGS .
| Kontroly výkonu |
|---|
| Určete množství volného místa ve spravované haldě. Určete počet připnutých objektů. |
Pokud se domníváte, že neexistují žádné oprávněné příčiny pro fragmentaci, obraťte se na zákaznickou službu a podporu Microsoftu.
Problém: pozastavení uvolňování paměti jsou moc dlouhá.
Uvolňování paměti funguje v tichém reálném čase, takže aplikace musí být schopná tolerovat některá pozastavení. Kritériem pro měkký reálný čas je to, že 95% operací se musí dokončit včas.
V případě souběžného uvolňování paměti můžou spravovaná vlákna běžet během shromažďování, což znamená, že pozastavení jsou velmi minimální.
Dočasné uvolňování paměti (generace 0 a 1) jsou poslední jenom několik milisekund, takže snížení pauz většinou není proveditelné. Můžete ale snížit počet pozastavení v kolekcích 2. generace změnou vzoru požadavků na přidělení aplikací.
Další přesnější metodou je použít události ETW pro uvolňování paměti. Časování pro kolekce můžete najít přidáním rozdílů časových razítek pro posloupnost událostí. Celá sekvence kolekce zahrnuje pozastavení prováděcího modulu, uvolňování paměti samotného a obnovení spouštěcího modulu.
Pomocí oznámení o uvolňování paměti můžete zjistit, jestli se server chystá mít kolekci 2. generace, a jestli žádosti o přesměrování na jiný server můžou způsobit problémy s pozastavením.
| Kontroly výkonu |
|---|
| Určete dobu v uvolňování paměti. Určete, co způsobilo uvolňování paměti. |
Problém: generace 0 je moc velká.
Generace 0 pravděpodobně bude mít větší počet objektů v 64 systému, zvlášť když použijete uvolňování paměti serveru místo uvolnění paměti pracovní stanice. Důvodem je to, že prahová hodnota pro aktivaci uvolňování paměti generace 0 je v těchto prostředích vyšší, a kolekce generace 0 může být mnohem větší. Zvýšení výkonu je vylepšeno, pokud aplikace přiděluje více paměti před aktivací uvolňování paměti.
Problém: využití CPU během uvolňování paměti je příliš vysoké.
Využití CPU bude během uvolňování paměti vysoké. Pokud se v uvolňování paměti stráví významné množství času zpracování, počet kolekcí je příliš častý nebo kolekce je trvalá příliš dlouho. Zvýšená míra přidělení objektů na spravované haldě způsobuje, že se uvolňování paměti objevuje častěji. Snížení míry přidělení omezí četnost uvolňování paměti.
Sazby přidělení můžete sledovat pomocí Allocated Bytes/second čítače výkonu. Další informace najdete v tématu čítače výkonu v rozhraní .NET.
Doba trvání kolekce je primárně faktorem počtu objektů, které jsou po přidělení zachovány. Systém uvolňování paměti musí projít velkým množstvím paměti, pokud je stále shromažďováno mnoho objektů. Práce na komprimaci pozůstalých je časově náročná. Chcete-li určit, kolik objektů bylo zpracováno během kolekce, nastavte zarážku v ladicím programu na konci uvolňování paměti pro zadanou generaci.
| Kontroly výkonu |
|---|
| Zjistěte, jestli je vysoké využití procesoru způsobeno uvolňováním paměti. Nastavte zarážku na konci uvolňování paměti. |
Pokyny pro řešení potíží
Tato část popisuje pokyny, které byste měli vzít v úvahu při zahájení šetření.
Uvolnění paměti pracovní stanice nebo serveru
Určete, zda používáte správný typ uvolňování paměti. Pokud vaše aplikace používá více vláken a instancí objektů, použijte místo uvolňování paměti pracovních stanic Server uvolňování paměti serveru. Uvolňování paměti serveru funguje ve více vláknech, zatímco uvolňování paměti pracovní stanice vyžaduje více instancí aplikace, aby spouštěla vlastní vlákna uvolňování paměti a mohla konkurovat času procesoru.
Aplikace, která má nízké zatížení a provádí úlohy na pozadí, jako je například služba, může použít uvolňování paměti pracovní stanice se zakázaným souběžným uvolňováním paměti.
Kdy změřit velikost spravované haldy
Pokud nepoužíváte Profiler, budete muset vytvořit jednotný měřicí vzor pro efektivní diagnostiku problémů s výkonem. Pro vytvoření plánu Vezměte v úvahu následující body:
Pokud měříte po uvolnění paměti 2. generace, celá spravovaná halda bude bez uvolnění paměti (nedoručené objekty).
Pokud měříte hned po uvolnění paměti generace 0, objekty v generacích 1 a 2 nebudou dosud shromažďovány.
Pokud měříte těsně před uvolňováním paměti, měříte co nejvíce přidělení, než začne uvolňování paměti.
Měření během uvolňování paměti je problematické, protože datové struktury uvolňování paměti nejsou v platném stavu pro procházení a nemusí být schopné poskytnout kompletní výsledky. Toto chování je úmyslné.
Pokud používáte uvolňování paměti pracovní stanice s souběžným uvolňováním paměti, uvolněné objekty se nekomprimuje, takže velikost haldy může být stejná nebo větší (fragmentace se může zdát, že je větší).
Souběžné uvolňování paměti v generaci 2 je zpožděno, pokud je zatížení fyzické paměti příliš vysoké.
Následující postup popisuje, jak nastavit zarážku, abyste mohli změřit spravovanou haldu.
Nastavení zarážky na konci uvolňování paměti
V programu WinDbg s načteným rozšířením ladicího programu SOS zadejte následující příkaz:
knihovny mscorwks BP WKS:: GCHeap:: RestartEE "j (DWO (knihovny Mscorwks! WKS:: GCHeap:: GcCondemnedGeneration) = = 2) ' KB '; ' g ' "
kde GcCondemnedGeneration je nastaveno na požadovanou generaci. Tento příkaz vyžaduje soukromé symboly.
Tento příkaz vynutí přerušení, pokud je RestartEE provedeno po uvolnění objektů generace 2 pro uvolňování paměti.
V uvolňování paměti serveru pouze jedno vlákno volá RestartEE, takže během uvolňování paměti 2. generace dojde k zarážce pouze jednou.
Postupy kontroly výkonu
Tato část popisuje následující postupy k izolaci příčiny problému s výkonem:
Zjištění, zda je problém způsoben uvolňováním paměti
Prověřte následující dvě čítače výkonu paměti:
% Času v GC. Zobrazuje procento uplynulého času stráveného prováděním uvolňování paměti po posledním cyklu uvolňování paměti. Pomocí tohoto čítače určíte, zda je uvolňování paměti příliš mnoho času na zpřístupnění spravovaného prostoru haldy. Pokud je doba strávená uvolňováním paměti poměrně nízká, může to znamenat problém s prostředky mimo spravovanou haldu. Tento čítač nemusí být přesný, pokud je zapojeno souběžné a uvolňování paměti na pozadí.
# Celkový počet potvrzených bajtů Zobrazuje velikost virtuální paměti, která je aktuálně potvrzena systémem uvolňování paměti. Pomocí tohoto čítače určíte, zda paměť využívaná systémem uvolňování paměti je nadměrná část paměti, kterou vaše aplikace používá.
Většina čítačů výkonu paměti se aktualizuje na konci každého uvolňování paměti. Proto nemusí odrážet aktuální podmínky, o kterých chcete získat informace.
Chcete-li určit, zda je výjimka nedostatek paměti spravovaná
v ladicím programu WinDbg nebo Visual Studio s načteným rozšířením ladicího programu SOS zadejte příkaz výjimka tisku (pe):
! PE
Pokud je výjimka spravovaná, OutOfMemoryException je zobrazena jako typ výjimky, jak je znázorněno v následujícím příkladu.
Exception object: 39594518 Exception type: System.OutOfMemoryException Message: <none> InnerException: <none> StackTrace (generated):Pokud výstup neurčuje výjimku, je nutné určit, ze kterého vlákna je výjimka nedostatek paměti. Zadejte následující příkaz v ladicím programu pro zobrazení všech vláken s jejich zásobníky volání:
~*Knowledge
Vlákno se zásobníkem, který obsahuje volání výjimek, je určeno
RaiseTheExceptionargumentem. Toto je spravovaný objekt výjimky.28adfb44 7923918f 5b61f2b4 00000000 5b61f2b4 mscorwks!RaiseTheException+0xa0Pomocí následujícího příkazu můžete vypsat vnořené výjimky.
! PE – vnořené
Pokud nenajdete žádné výjimky, výjimka nedostatek paměti pochází z nespravovaného kódu.
Určení, kolik virtuální paměti je možné rezervovat
Do WinDbg s načteným rozšířením ladicího programu SOS zadejte následující příkaz, který získá největší bezplatnou oblast:
!address -summary
Zobrazí se největší bezplatná oblast, jak je znázorněno v následujícím výstupu.
Largest free region: Base 54000000 - Size 0003A980V tomto příkladu je velikost největší volné oblasti přibližně 2 4000 kB (3A980 v šestnáctkovém formátu). Tato oblast je mnohem menší, než systém uvolňování paměti potřebuje pro segment.
-nebo-
Použijte příkaz vmstat:
!vmstat
Největší volná oblast je největší hodnota ve sloupci MAXIMUM, jak je znázorněno v následujícím výstupu.
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
Zjištění, jestli je k dispozici dostatek fyzické paměti
Spusťte Windows Správce úloh.
Na kartě Výkon se podívejte na potvrzenou hodnotu. (V Windows 7 se podívejte na Potvrzení (KB) ve skupině Systém.)
Pokud se celkový součet blíží limitu, dochází vám fyzická paměť.
Určení, kolik paměti spravovaná halda potvrzuje
Pomocí čítače výkonu paměti získejte počet bajtů,
# Total committed byteskteré spravovaná halda potvrzuje. Systém uvolňování paměti podle potřeby potvrdí bloky dat v segmentu, ne všechny najednou.Poznámka
Nepoužívejte čítač výkonu, protože nepředstavuje skutečné využití paměti
# Bytes in all Heapsspravovanou haldou. Velikost generace je zahrnutá v této hodnotě a je ve skutečnosti její prahovou velikostí, to znamená velikost, která vyvolává uvolňování paměti, pokud je generování naplněno objekty. Proto je tato hodnota obvykle nula.
Určení paměti rezerv spravované haldy
Použijte
# Total reserved bytesčítač výkonu paměti.Systém uvolňování paměti rezervuje paměť v segmentech a pomocí příkazu eeheap můžete určit, kde segment začíná.
Důležité
I když můžete určit velikost paměti, kterou systém uvolňování paměti přiděluje pro jednotlivé segmenty, velikost segmentu je specifická pro implementaci a může se kdykoli změnit, a to i v pravidelných aktualizacích. Vaše aplikace by nikdy neměla provádět předpoklady týkající se konkrétní velikosti segmentu nebo na ní záviset, ani by se neměla pokoušet o konfiguraci dostupné paměti pro přidělení segmentů.
Do ladicího programu WinDbg nebo Visual Studio s načteným rozšířením ladicího programu SOS zadejte následující příkaz:
!eeheap -gc
Výsledek je následující.
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)Adresy označené segmentem jsou počátečními adresami segmentů.
Určení velkých objektů v generaci 2
Do ladicího programu WinDbg nebo Visual Studio s načteným rozšířením ladicího programu SOS zadejte následující příkaz:
!dumpheap –stat
Pokud je spravovaná halda velká, může dokončení výpisu paměti chvíli trvat.
Analýzu můžete začít analyzovat z posledních několika řádků výstupu, protože vykreslují objekty, které používají nejvíce místa. Například:
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 objectsPosledním uvedeným objektem je řetězec, který zabírá nejvíce místa. Můžete svou aplikaci prozkoumat a podívat se, jak lze objekty řetězců optimalizovat. Pokud chcete zobrazit řetězce v rozmezí 150 až 200 bajtů, zadejte následující:
!dumpheap -type System.String -min 150 -max 200
Příklad výsledků je následující.
Address MT Size Gen 1875d2c0 790fa3e0 152 2 System.String HighlightNullStyle_Blotter_PendingOrder-11_Blotter_PendingOrder-11 …Použití celého čísla místo řetězce pro ID může být efektivnější. Pokud se stejný řetězec opakuje tisícekrát, zvažte stáže řetězců. Další informace o stáži řetězců najdete v referenčním tématu pro String.Intern metodu .
Určení odkazů na objekty
Do windbg s načteným rozšířením ladicího programu SOS zadejte následující příkaz, který vyjádře odkazy na objekty:
!gcroot
-or-Pokud chcete určit odkazy na konkrétní objekt, zadejte adresu:
!gcroot 1c37b2ac
Kořeny nalezené v zásobníkech mohou být falešně pozitivní. Další informace získáte pomocí příkazu
!help gcroot.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 484Dokončení příkazu gcroot může trvat dlouhou dobu. Každý objekt, který není uvolněn systémem uvolňování paměti, je živý objekt. To znamená, že některý kořen se přímo nebo nepřímo drží na objektu, takže gcroot by měl vrátit informace o cestě k objektu. Měli byste prozkoumat vrácené grafy a podívat se, proč se na tyto objekty stále odkazuje.
Určení, jestli byla spuštěna finalizační metoda
Spusťte testovací program, který obsahuje následující kód:
GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect();Pokud test problém vyřeší, znamená to, že systém uvolňování paměti neuvolňuje objekty, protože finalizační metody pro tyto objekty byly pozastaveny. Metoda GC.WaitForPendingFinalizers umožňuje finalizačním metodám provádět úkoly a opravuje problém.
Určení, zda existují objekty čekající na dokončení
Do ladicího programu WinDbg nebo Visual Studio s načteným rozšířením ladicího programu SOS zadejte následující příkaz:
!finalizequeue
Podívejte se na počet objektů, které jsou připravené k dokončení. Pokud je číslo vysoké, musíte prozkoumat, proč tyto finalizační metody nemohou vůbec postupovat nebo nemohou dostatečně rychle postupovat.
Pokud chcete získat výstup vláken, zadejte následující příkaz:
!threads -special
Tento příkaz poskytuje výstup, například následující.
OSID Special thread type 2 cd0 DbgHelper 3 c18 Finalizer 4 df0 GC SuspendEEVlákno finalizační metody označuje, která finalizační metoda (pokud existuje) se právě spouštěná. Pokud vlákno finalizační metody nese používá žádné finalizační metody, čeká na to, až událost řekne, že má provést svou práci. Ve většině času uvidíte vlákno finalizační metody v tomto stavu, protože běží na THREAD_HIGHEST_PRIORITY a spuštění finalizačních metod by mělo být dokončeno, pokud nějaké jsou, velmi rychle.
Určení volného místa ve spravované haldě
Do ladicího programu WinDbg nebo Visual Studio s načteným rozšířením ladicího programu SOS zadejte následující příkaz:
!dumpheap -type Free -stat
Tento příkaz zobrazí celkovou velikost všech volných objektů na spravované haldě, jak je znázorněno v následujícím příkladu.
total 230 objects Statistics: MT Count TotalSize Class Name 00152b18 230 40958584 Free Total 230 objectsPokud chcete zjistit volné místo ve generaci 0, zadejte následující příkaz pro informace o spotřebě paměti podle generace:
!eeheap -gc
Tento příkaz zobrazí výstup podobný následujícímu. Poslední řádek zobrazuje dočasný 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)Vypočítejte prostor používaný generováním 0:
? 49e05d04-0x49521f8c
Výsledek je následující. Generace 0 je přibližně 9 MB.
Evaluate expression: 9321848 = 008e3d78Následující příkaz vy výpisem volného místa v rozsahu generace 0:
!dumpheap -type Free -stat 0x49521f8c 49e05d04
Výsledek je následující.
------------------------------ 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 objectsTento výstup ukazuje, že část haldy generace 0 používá 9 MB místa pro objekty a má 7 MB volného místa. Tato analýza ukazuje, do jaké míry generace 0 přispívá k fragmentaci. Toto množství využití haldy by se mělo snížit z celkového množství jako příčiny fragmentace dlouhodobými objekty.
Určení počtu připnutých objektů
Do ladicího programu WinDbg nebo Visual Studio s načteným rozšířením ladicího programu SOS zadejte následující příkaz:
!gchandles
Zobrazené statistiky zahrnují počet připnutých popisovačů, jak ukazuje následující příklad.
GC Handle Statistics: Strong Handles: 29 Pinned Handles: 10
Určení doby v uvolňování paměti
Zkontrolujte
% Time in GCčítač výkonu paměti.Hodnota se vypočítá pomocí intervalu vzorku. Vzhledem k tomu, že se čítače aktualizují na konci každého uvolňování paměti, aktuální vzorek bude mít stejnou hodnotu jako předchozí vzorek, pokud během intervalu nedošlo k žádným kolekcím.
Čas shromažďování se získá vynásobením času intervalu vzorku procentuální hodnotou.
Následující data ukazují čtyři intervaly vzorkování po dvou sekundách pro 8sekundovou studii. Sloupce , a zobrazují počet uvolňování paměti, ke kterým došlo
Gen0Gen1během tohotoGen2intervalu pro toto generování.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 3Tyto informace se nezminí o tom, kdy došlo k uvolnění paměti, ale můžete určit počet uvolňování paměti, ke kterým došlo v časovém intervalu. V případě nejhoršího případu bylo dokončeno uvolňování paměti desáté generace 0 na začátku druhého intervalu a jedenácté uvolňování paměti 0 na konci pátého intervalu. Doba mezi koncem desátého a koncem jedenáctého uvolňování paměti je přibližně 2 sekundy a čítač výkonu zobrazuje 3%, takže doba trvání jedenáctého uvolňování paměti 0 (2 sekundy * 3% = 60ms).
V tomto příkladu je 5 teček.
Interval Gen0 Gen1 Gen2 % Time in GC 1 9 3 1 3 2 10 3 1 1 3 11 4 2 1 4 11 4 2 1 5 11 4 2 20Druhá kolekce paměti 2. generace začala během třetího intervalu a skončila v pátém intervalu. Za nejhorší případ byl poslední uvolňování paměti pro kolekci generace 0, která skončila na začátku druhého intervalu, a uvolnění paměti 2. generace bylo dokončeno na konci pátého intervalu. Proto je čas mezi koncem uvolňování paměti generace 0 a koncem uvolňování paměti 2. generace 4 sekundy. Vzhledem k tomu
% Time in GC, že čítač je 20%, pak maximální doba, po kterou by bylo možné učinit uvolňování paměti 2. generace, je (4 sekundy * 20% = 800ms).Alternativně můžete určit délku uvolňování paměti pomocí událostí ETW pro uvolňování pamětia analyzovat informace a určit dobu trvání uvolňování paměti.
Například následující data ukazují sekvenci události, ke které došlo během nesouběžného uvolňování paměti.
Timestamp Event name 513052 GCSuspendEEBegin_V1 513078 GCSuspendEEEnd 513090 GCStart_V1 517890 GCEnd_V1 517894 GCHeapStats 517897 GCRestartEEBegin 517918 GCRestartEEEndPozastavení spravovaného vlákna trvalo 26us (
GCSuspendEEEnd–GCSuspendEEBegin_V1).Skutečné uvolňování paměti trvalo 4,8 ms (
GCEnd_V1–GCStart_V1).Obnovení spravovaných vláken trvalo 21us (
GCRestartEEEnd–GCRestartEEBegin).Následující výstup poskytuje příklad pro uvolňování paměti na pozadí a obsahuje pole proces, vlákno a událost. (Ne všechna data jsou zobrazena.)
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 4372GCStart_V1Událost v 42504816 označuje, že se jedná o uvolňování paměti na pozadí, protože poslední pole je1. To se v tomto případě stalo uvolňováním paměti. 102019.K
GCStartudálosti dochází, protože před spuštěním uvolňování paměti na pozadí je zapotřebí dočasné uvolňování paměti. To se v tomto případě stalo uvolňováním paměti. 102020.V 42514170, č. uvolnění paměti. 102020 dokončí. Spravovaná vlákna jsou v tuto chvíli restartována. Tato operace je dokončena ve vláknu 4372, které aktivovalo tuto kolekci paměti na pozadí.
Na vlákně 4744 dojde k pozastavení. Toto je jediná doba, s jakou má uvolňování paměti na pozadí pozastavit spravovaná vlákna. Toto trvání je přibližně 99ms ((63784407-63685394)/1000).
GCEndUdálost pro uvolňování paměti na pozadí je 89931423. To znamená, že uvolňování paměti na pozadí uplynulo pro přibližně 47seconds ((89931423-42504816)/1000).I když jsou spuštěná spravovaná vlákna, vidíte libovolný počet dočasných uvolňování paměti, ke kterým dochází.
Určení toho, co vyvolalo uvolňování paměti
v ladicím programu WinDbg nebo Visual Studio s načteným rozšířením ladicího programu SOS zadejte následující příkaz pro zobrazení všech vláken s jejich zásobníky volání:
~*Knowledge
Tento příkaz zobrazí výstup podobný následujícímu.
0012f3b0 79ff0bf8 mscorwks!WKS::GCHeap::GarbageCollect 0012f454 30002894 mscorwks!GCInterface::CollectGeneration+0xa4 0012f490 79fa22bd fragment_ni!request.Main(System.String[])+0x48Pokud uvolňování paměti bylo způsobeno oznámením o nedostatku paměti z operačního systému, je zásobník volání podobný, s tím rozdílem, že vlákno je finalizační vlákno. Finalizační vlákno získá oznámení o asynchronní nedostatku paměti a vyřadí uvolňování paměti.
Pokud uvolňování paměti bylo způsobeno přidělením paměti, zásobník se zobrazí takto:
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[])+0x153Nakonec se volá pomocník za běhu (
JIT_New*)GCHeap::GarbageCollectGeneration. Pokud zjistíte, že jsou uvolňovány paměti generace 2 způsobeny přidělením, je nutné určit, které objekty jsou shromažďovány uvolňováním paměti 2. generace a jak se jim vyhnout. To znamená, že chcete určit rozdíl mezi začátkem a koncem uvolňování paměti 2. generace a objekty, které způsobily kolekci 2. generace.Zadejte například následující příkaz v ladicím programu, který zobrazí začátek kolekce generace 2:
! dumpheap – stat
Příklad výstupu (zkráceně pro zobrazení objektů, které používají nejvíce místa):
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 objectsOpakujte tento příkaz na konci generace 2:
! dumpheap – stat
Příklad výstupu (zkráceně pro zobrazení objektů, které používají nejvíce místa):
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 objectsdouble[]Objekty zmizely na konci výstupu, což znamená, že byly shromážděny. Tyto objekty jsou přibližně 70 MB. Zbývající objekty se nezměnily mnohem. Proto by tytodouble[]objekty byly důvodem, proč došlo k této chybě uvolňování paměti 2. generace. V dalším kroku zjistíte, pročdouble[]jsou objekty tam a proč uhynulé. Můžete požádat vývojáře kódu, ze kterého pocházejí tyto objekty, nebo můžete použít příkaz gcroot .
Určení, zda vysoké využití procesoru je způsobeno uvolňováním paměti
Proveďte korelaci
% Time in GChodnoty čítače výkonu paměti s časem procesu.Pokud je
% Time in GChodnota špičky ve stejnou dobu jako doba zpracování, uvolňování paměti způsobuje vysoké využití procesoru. V opačném případě profilujte aplikaci, abyste zjistili, kde dochází k vysokému využití.