Události
Vytváření inteligentních aplikací
17. 3. 21 - 21. 3. 10
Připojte se k řadě meetupů a vytvořte škálovatelná řešení AI založená na skutečných případech použití s kolegy vývojáři a odborníky.
ZaregistrovatTento prohlížeč se už nepodporuje.
Upgradujte na Microsoft Edge, abyste mohli využívat nejnovější funkce, aktualizace zabezpečení a technickou podporu.
Tento článek popisuje problémy související s uvolňováním paměti a využitím paměti. Řeší problémy týkající se spravované haldy a vysvětluje, jak minimalizovat dopad uvolňování paměti na vaše aplikace. Každý problém obsahuje odkazy na postupy, které můžete použít ke zkoumání problémů.
Následující části popisují nástroje, které jsou k dispozici pro zkoumání problémů s využitím paměti a uvolňováním paměti. Postupy uvedené dále v tomto článku se týkají těchto nástrojů.
Ke shromažďování dat o výkonu můžete použít čítače výkonu. Pokyny najdete v tématu Profilace modulu runtime. Kategorie Paměť .NET CLR čítačů výkonu, jak je popsáno v čítačích výkonu v .NET, poskytuje informace o uvolňování paměti.
Ladicí program systému Windows (WinDbg) můžete použít ke kontrole objektů ve spravované haldě.
Chcete-li nainstalovat WinDbg, nainstalujte nástroje ladění pro Windows ze stránky Stáhnout nástroje ladění pro Windows .
Trasování událostí pro Windows (ETW) je systém trasování, který doplňuje podporu profilace a ladění poskytované rozhraním .NET. Počínaje rozhraním .NET Framework 4 zachytává události tras uvolňování paměti pro Windows užitečné informace pro analýzu spravované haldy ze statistického hlediska. Například GCStart_V1
událost, která se vyvolá při spuštění uvolňování paměti, poskytuje následující informace:
Protokolová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 protokolování je možné korelovat události aplikace i události uvolňování paměti a 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 na konci požadavku klienta.
Rozhraní clr (Common Language Runtime) profilace 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átoři můžou poskytovat komplexní informace. Složité profilátory ale můžou potenciálně změnit chování aplikace.
Počínaje rozhraním .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.
Prvním krokem je určení, jestli je problém skutečně uvolňování paměti. Pokud zjistíte, že se jedná o řešení problému, vyberte v následujícím seznamu.
Existují dva legitimní případy, kdy může dojít k vyvolání spravovaného OutOfMemoryException objektu:
Dochází k virtuální paměti.
Systém uvolňování paměti přiděluje paměť v segmentech předem určené velikosti. Pokud přidělení vyžaduje další segment, ale v prostoru virtuální paměti procesu není žádný souvislý volný blok, přidělení spravované haldy se nezdaří.
Nemá dostatek fyzické paměti k přidělení.
Kontroly výkonu |
---|
Určete, jestli je výjimka mimo paměť spravovaná. Určete, kolik virtuální paměti je možné rezervovat. Určete, jestli je dostatek fyzické paměti. |
Pokud zjistíte, že výjimka není legitimní, obraťte se na zákaznickou službu a podporu Společnosti Microsoft s následujícími informacemi:
Běžným předpokladem je, že zobrazení využití paměti na kartě Výkon ve Správci úloh systému Windows může znamenat, 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, je nutné změřit spravovanou haldu v průběhu času a určit případné vzory.
Pokud zjistíte, že příčinou problému není spravovaná halda, musíte použít nativní ladění.
Pokud se zdá, že objekty nejsou uvolněny podle očekávání pro uvolňování paměti, je nutné určit, zda existují silné odkazy na tyto objekty.
K tomuto problému může dojít také v případě, že nedošlo k uvolnění paměti pro generování, které obsahuje mrtvý objekt, což značí, že finalizátor mrtvého objektu nebyl spuštěn. To je například možné, když používáte aplikaci STA (Single-Threaded Apartment) a vlákno, které obsluhuje frontu finalizátoru nemůže do ní volat.
Kontroly výkonu |
---|
Zkontrolujte odkazy na objekty. Určete, jestli byl finalizátor spuštěn. Určete, jestli existují objekty, které čekají na dokončení. |
Úroveň fragmentace se vypočítá jako poměr volného místa nad celkovou přidělenou pamětí pro generování. U generace 2 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.
Když máte ve generaci 0 hodně volného místa, není problém, protože se jedná o generaci, ve které jsou přidělovány nové objekty.
Fragmentace se vždy vyskytuje v haldě velkého objektu, protože není komprimovaná. Volné objekty, které sousedí, jsou přirozeně sbalené do jednoho prostoru, aby vyhovovaly velkým žádostem o přidělení objektů.
Fragmentace může být problémem generace 1 a generace 2. Pokud mají tyto generace po uvolňování paměti velké množství volného místa, může být potřeba upravit využití objektů aplikace 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á, bylo možné připnout příliš mnoho objektů.
Pokud fragmentace virtuální paměti brání uvolňování paměti v přidávání segmentů, může to být jedna z následujících příčin:
Časté načítání a uvolňování mnoha malých sestavení.
Při spolupráci s nespravovaným kódem držíte příliš mnoho odkazů na objekty MODELU COM.
Vytvoření velkých přechodných objektů, což způsobuje, že velká halda objektu často přiděluje a uvolní 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 sníží frekvence přidělování segmentů. Toho dosáhnete pomocí příznaku STARTUP_HOARD_GC_VM v STARTUP_FLAGS výčtu.
Pokud si myslíte, že nedochází k žádné oprávněné příčině fragmentace, obraťte se na zákaznickou službu Microsoftu a podporu.
Uvolňování paměti funguje v měkké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, že 95 % operací musí být dokončeno včas.
V souběžné uvolňování paměti mohou spravovaná vlákna běžet během shromažďování, což znamená, že pozastavení je velmi minimální.
Dočasné uvolňování paměti (generace 0 a 1) trvá jen několik milisekund, takže snížení pozastavení obvykle není možné. Pozastavení v kolekcích 2. generace ale můžete snížit změnou vzoru žádostí o přidělení aplikací.
Další přesnější metodou je použití událostí trasování událostí pro Windows uvolňování paměti. Časování kolekcí najdete přidáním rozdílů časových razítek pro posloupnost událostí. Celá sekvence kolekce zahrnuje pozastavení prováděcího modulu, samotné uvolňování paměti a obnovení prováděcího modulu.
Pomocí oznámení o uvolňování paměti můžete určit, jestli se server chystá mít kolekci generace 2 a jestli přesměrování požadavků na jiný server může usnadnit jakékoli problémy s pozastavením.
Generace 0 pravděpodobně bude mít větší počet objektů v 64bitovém systému, zejména pokud místo uvolňování paměti pracovní stanice používáte uvolňování paměti serveru. Důvodem je to, že prahová hodnota pro aktivaci uvolňování paměti 0 generace je v těchto prostředích vyšší a kolekce generace 0 mohou být mnohem větší. Výkon se zlepší, když aplikace přiděluje více paměti před aktivací uvolňování paměti.
Využití procesoru bude během uvolňování paměti vysoké. Pokud je v uvolňování paměti vynaloženo značné množství času procesu, je počet kolekcí příliš častý nebo kolekce trvá příliš dlouho. Vyšší míra přidělování objektů ve spravované haldě způsobuje častější uvolňování paměti. Snížením míry přidělování se sníží frekvence uvolňování paměti.
Sazby přidělení můžete monitorovat pomocí čítače výkonu Allocated Bytes/second
. Další informace naleznete v tématu Čítače výkonu v .NET.
Doba trvání kolekce je primárně faktorem počtu objektů, které přežijí po přidělení. Uvolňování paměti musí projít velkým množstvím paměti, pokud mnoho objektů zůstane shromážděno. Práce na komprimování přeživších je časově náročná. Chcete-li zjistit, 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ůsobené uvolňováním paměti. Nastavte zarážku na konci uvolňování paměti. |
Tato část popisuje pokyny, které byste měli zvážit při zahájení vyšetřování.
Zjistěte, jestli 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í stanice uvolňování paměti serveru. Uvolňování paměti serveru funguje na více vláknech, zatímco uvolňování paměti pracovní stanice vyžaduje více instancí aplikace ke spuštění vlastních vláken uvolňování paměti a soutěžit o čas procesoru.
Aplikace, která má nízké zatížení a provádí úlohy zřídka na pozadí, jako je 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.
Pokud nepoužíváte profiler, budete muset vytvořit konzistentní model měření, abyste mohli efektivně diagnostikovat problémy s výkonem. Při vytváření plánu zvažte následující body:
Následující postup popisuje, jak nastavit zarážku, abyste mohli měřit spravovanou haldu.
Ve WinDbg s načteným rozšířením ladicího programu SOS zadejte následující příkaz:
bp mscorwks!WKS::GCHeap::RestartEE "j (dwo(mscorwks!WKS::GCHeap::GcCondemnedGeneration)==2) 'kb';'g'"
Nastavte GcCondemnedGeneration
na požadovanou generaci. Tento příkaz vyžaduje privátní symboly.
Tento příkaz vynutí přerušení, pokud RestartEE
se spustí po uvolnění objektů generace 2 pro uvolňování paměti.
V uvolňování paměti serveru volá pouze jedno vlákno RestartEE
, takže zarážka bude probíhat pouze jednou během uvolňování paměti generace 2.
Tato část popisuje následující postupy izolace příčiny vašeho problému s výkonem:
Projděte si následující dva čítače výkonu paměti:
% času v GC. Zobrazí procento uplynulého času stráveného provedením uvolňování paměti po posledním cyklu uvolňování paměti. Pomocí tohoto čítače určete, jestli systém uvolňování paměti tráví příliš mnoho času, aby byl dostupný spravovaný prostor haldy. Pokud je čas strávený v uvolňování paměti relativně nízký, může to znamenat problém s prostředkem mimo spravovanou haldu. Tento čítač nemusí být přesný, pokud je zapojen souběžný uvolňování paměti nebo uvolňování paměti na pozadí.
# Celkový počet potvrzených bajtů. Zobrazí velikost virtuální paměti aktuálně potvrzené systémem uvolňování paměti. Pomocí tohoto čítače určete, jestli je paměť spotřebovaná uvolňováním paměti nadměrnou částí paměti, kterou vaše aplikace používá.
Většina čítačů výkonu paměti se aktualizuje na konci každé uvolňování paměti. Proto nemusí odrážet aktuální podmínky, o kterých chcete informace.
V ladicím programu WinDbg nebo Visual Studio s načteným rozšířením ladicího programu SOS zadejte příkaz print exception (pe
):
!pe
Pokud je výjimka spravovaná, OutOfMemoryException zobrazí se 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čí výjimku, musíte určit, které vlákno výjimku z nedostatku paměti pochází. Zadáním následujícího příkazu v ladicím programu zobrazíte všechna vlákna s jejich zásobníky volání:
~\*kb
Vlákno se zásobníkem, který má volání výjimek, je označen argumentem RaiseTheException
. Toto je objekt spravované výjimky.
28adfb44 7923918f 5b61f2b4 00000000 5b61f2b4 mscorwks!RaiseTheException+0xa0
K výpisu vnořených výjimek můžete použít následující příkaz.
!pe -nested
Pokud nenajdete žádné výjimky, výjimka mimo paměť pochází z nespravovaného kódu.
Ve 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 0003A980
V tomto příkladu je velikost největší volné oblasti přibližně 24000 kB (3A980 v šestnáctkové soustavě). Tato oblast je mnohem menší než to, co systém uvolňování paměti potřebuje pro segment.
-Nebo-
vmstat
Použijte příkaz:
!vmstat
Největší bezplatná oblast je největší hodnotou 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
Spusťte Správce úloh systému Windows.
Performance
Na kartě se podívejte na potvrzenou hodnotu. (Ve Windows 7 se podívejte na Commit (KB)
. System group
)
Pokud je blízko Total
fyzické paměti, dochází k nedostatku Limit
fyzické paměti.
# Total committed bytes
Pomocí čítače výkonu paměti získáte počet bajtů, které spravovaná halda potvrdí. 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 # Bytes in all Heaps
, protože nepředstavuje skutečné využití paměti spravovanou haldou. Velikost generování je zahrnuta v této hodnotě a je ve skutečnosti její prahová velikost, tj. velikost, která indukuje uvolňování paměti, pokud je generování naplněno objekty. Proto je tato hodnota obvykle nula.
Použijte čítač výkonu # Total reserved bytes
paměti.
Systém uvolňování paměti si vyhrazuje paměť v segmentech a pomocí příkazu můžete určit, kde segment začíná eeheap
.
Důležité
I když můžete určit velikost paměti, kterou systém uvolňování paměti přiděluje pro každý segment, velikost segmentu je specifická pro implementaci a může se kdykoli změnit, včetně pravidelných aktualizací. Vaše aplikace by nikdy neměla provádět předpoklady týkající se konkrétní velikosti segmentu ani záviset na ní, ani by se neměla pokoušet konfigurovat množství paměti dostupné pro přidělení segmentů.
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:
!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ů.
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:
!dumpheap –stat
Pokud je spravovaná halda velká, dumpheap
může dokončení chvíli trvat.
Můžete začít analyzovat z posledních několika řádků výstupu, protože uvádějí objekty, které používají nejvíce místa. Pří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 objects
Poslední uvedený objekt je řetězec a zabírá nejvíce místa. Aplikaci můžete prozkoumat a zjistit, jak je možné optimalizovat objekty řetězců. Pokud chcete zobrazit řetězce v rozsahu 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 prokládání řetězců. Další informace o prokládání řetězců naleznete v referenčním tématu pro metodu String.Intern .
Ve WinDbg s načteným rozšířením ladicího programu SOS zadejte následující příkaz, který zobrazí odkazy na objekty:
!gcroot
-Nebo-
Pokud chcete určit odkazy na konkrétní objekt, uveďte adresu:
!gcroot 1c37b2ac
Kořeny nalezené na stackech mohou být falešně pozitivní. Další informace potřebujete 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 484
Dokončení gcroot
příkazu může trvat delší dobu. Libovolný objekt, který není uvolněný uvolňováním paměti, je živý objekt. To znamená, že některý kořenový adresář přímo nebo nepřímo drží na objektu, takže gcroot
by se měly vrátit informace o cestě k objektu. Měli byste prozkoumat vrácené grafy a zjistit, proč se na tyto objekty stále odkazují.
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 uvolňování paměti neobsáhlo objekty, protože finalizační metody pro tyto objekty byly pozastaveny. Metoda GC.WaitForPendingFinalizers umožňuje finalizátorům dokončit své úkoly a opravit problém.
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:
!finalizequeue
Podívejte se na počet objektů, které jsou připravené k dokončení. Pokud je číslo vysoké, musíte zkontrolovat, proč tyto finalizátory vůbec nemohou pokračovat nebo nemohou dostatečně rychle pokračovat.
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 SuspendEE
Vlákno finalizátoru označuje, který finalizátor je aktuálně spuštěn. Pokud vlákno finalizátoru nespouštět žádné finalizátory, čeká na událost, aby jí řekla, aby udělala svou práci. Ve většině případů uvidíte vlákno finalizátoru v tomto stavu, protože běží na THREAD_HIGHEST_PRIORITY a má dokončit spuštění finalizátorů, pokud existuje, velmi rychle.
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:
!dumpheap -type Free -stat
Tento příkaz zobrazí celkovou velikost všech volných objektů ve 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 objects
Pokud chcete určit 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, který používá generace 0:
? 49e05d04-0x49521f8c
Výsledek je následující. Generace 0 je přibližně 9 MB.
Evaluate expression: 9321848 = 008e3d78
Následující příkaz vygeneruje volné místo v rozsahu 0 generace:
!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 objects
Tento výstup ukazuje, že část haldy 0 generace používá 9 MB místa pro objekty a má 7 MB volného místa. Tato analýza ukazuje rozsah, do kterého generace 0 přispívá k fragmentaci. Toto množství využití haldy by mělo být zlevněno z celkové částky jako příčina fragmentace dlouhodobými objekty.
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:
!gchandles
Zobrazené statistiky zahrnují počet připnutých úchytů, jak ukazuje následující příklad.
GC Handle Statistics:
Strong Handles: 29
Pinned Handles: 10
Prozkoumejte čítač výkonu % Time in GC
paměti.
Hodnota se vypočítá pomocí ukázkového intervalu. Vzhledem k tomu, že se čítače aktualizují na konci každé uvolňování paměti, bude mít aktuální ukázka 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 s procentuální hodnotou.
Následující data ukazují čtyři intervaly vzorkování dvou sekund pro 8sekundovou studii. Sloupce Gen0
a Gen2
, Gen1
zobrazují celkový počet uvolňování paměti, které byly dokončeny do konce intervalu pro danou generaci.
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
Tyto informace se nezobrazují, když došlo k uvolňování paměti, ale můžete určit počet uvolňování paměti, ke kterým došlo v intervalu času. Za předpokladu nejhoršího případu se desátá generace 0 uvolňování paměti dokončila na začátku druhého intervalu a jedenáctá generace 0 uvolňování paměti skončila na konci třetího intervalu. Doba mezi koncem desátého a koncem jedenáctého uvolňování paměti je asi 2 sekundy a čítač výkonu ukazuje 3 %, takže doba trvání jedenácté generace 0 uvolňování paměti byla (2 sekundy * 3 % = 60 ms).
V dalším příkladu je pět intervalů.
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
Druhá generace 2 uvolňování paměti začala během čtvrtého intervalu a dokončena v pátém intervalu. Za předpokladu nejhoršího případu bylo poslední uvolňování paměti pro kolekci generace 0, která skončila na začátku třetího intervalu, a uvolňování paměti generace 2 skončilo na konci pátého intervalu. Proto je doba mezi koncem generování 0 uvolňování paměti a koncem uvolňování paměti 2. generace 4 sekundy. Vzhledem k tomu, že % Time in GC
čítač je 20 %, maximální doba potřebná pro uvolňování paměti generace 2 je (4 sekundy * 20 % = 800 ms).
Případně můžete určit délku uvolňování paměti pomocí událostí trasování událostí pro Windows uvolňování paměti a analyzovat informace, abyste určili dobu uvolňování paměti.
Například následující data ukazují sekvenci událostí, ke které došlo během nesouběrové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 GCRestartEEEnd
Pozastavení 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 obsahuje příklad pro uvolňování paměti na pozadí a obsahuje pole procesu, vlákna a události. (Nezobrazují se všechna data.)
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
Událost GCStart_V1
v 42504816 označuje, že se jedná o uvolňování paměti na pozadí, protože poslední pole je 1
. Tím se stane uvolňování paměti Ne. 102019.
K GCStart
události dochází, protože před spuštěním uvolňování paměti na pozadí je potřeba dočasné uvolňování paměti. Tím se stane uvolňování paměti č. 102020.
V 42514170 skončí uvolňování paměti č. 102020. Spravovaná vlákna se v tuto chvíli restartují. To je dokončeno ve vlákně 4372, které aktivovalo tuto uvolňování paměti na pozadí.
Na vlákně 4744 dochází k pozastavení. Jedná se o jediný čas, kdy musí uvolňování paměti na pozadí pozastavit spravovaná vlákna. Tato doba trvání je přibližně 99 ms ((63784407-63685394)/1000).
Událost GCEnd
uvolňování paměti na pozadí je na 89931423. To znamená, že uvolňování paměti na pozadí trvalo přibližně 47seconds ((89931423-42504816)/1000).
Zatímco jsou spravovaná vlákna spuštěná, můžete vidět libovolný počet dočasných uvolňování paměti, ke kterým dochází.
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, který zobrazí všechna vlákna s jejich zásobníky volání:
~*Kb
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[])+0x48
Pokud uvolňování paměti způsobilo oznámení o nedostatku paměti z operačního systému, zásobník volání je podobný s tím rozdílem, že vlákno je finalizační vlákno. Vlákno finalizátoru získá asynchronní oznámení o nedostatku paměti a vyvolá uvolňování paměti.
Pokud uvolnění paměti způsobilo přidělení 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[])+0x153
Pomocná rutina za běhu (JIT_New*
) nakonec zavolá GCHeap::GarbageCollectGeneration
. Pokud zjistíte, že uvolňování paměti 2. generace je způsobeno přidělením, musíte určit, které objekty jsou shromažďovány uvolňováním paměti generace 2 a jak se jim vyhnout. To znamená, že chcete určit rozdíl mezi startem a koncem uvolňování paměti generace 2 a objekty, které způsobily kolekci generace 2.
Zadejte například do ladicího programu následující příkaz, který zobrazí začátek kolekce generace 2:
!dumpheap –stat
Příklad výstupu (zkrácený, aby se zobrazily objekty, 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 objects
Opakujte příkaz na konci generace 2:
!dumpheap –stat
Příklad výstupu (zkrácený, aby se zobrazily objekty, 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 objects
Objekty double[]
zmizely z konce výstupu, což znamená, že byly shromážděny. Tyto objekty představují přibližně 70 MB. Zbývající objekty se moc nezměnily. Proto tyto double[]
objekty byly důvodem, proč došlo k této generaci 2 uvolňování paměti. Vaším dalším krokem je určit, proč double[]
tam jsou objekty a proč zemřely. Můžete se zeptat vývojáře kódu, odkud tyto objekty pocházejí, nebo můžete použít gcroot
příkaz.
Korelujte hodnotu čítače % Time in GC
výkonu paměti s časem procesu.
% Time in GC
Pokud se hodnota špičky současně s časem procesu, uvolňování paměti způsobuje vysoké využití procesoru. V opačném případě profilujte aplikaci a zjistěte, kde dochází k vysokému využití.
Zpětná vazba k produktu .NET
.NET je open source projekt. Vyberte odkaz pro poskytnutí zpětné vazby:
Události
Vytváření inteligentních aplikací
17. 3. 21 - 21. 3. 10
Připojte se k řadě meetupů a vytvořte škálovatelná řešení AI založená na skutečných případech použití s kolegy vývojáři a odborníky.
ZaregistrovatŠkolení
Postup výuky
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Dokumentace
Uvolňování paměti na pozadí - .NET
Přečtěte si o uvolňování paměti na pozadí v .NET a o tom, jak se liší v pracovní stanici a uvolňování paměti serveru.
Pracovní stanice vs. uvolňování paměti serveru (GC) - .NET
Přečtěte si o pracovní stanici a uvolňování paměti serveru v .NET.
Halda velkého objektu (LOH) ve Windows - .NET
Tento článek popisuje velké objekty, jejich správu pomocí uvolňování paměti .NET a vliv na výkon při používání velkých objektů.