Szemétgyűjtés és teljesítmény

Ez a cikk a szemétgyűjtéssel és a memóriahasználattal kapcsolatos problémákat ismerteti. Foglalkozik a felügyelt halommal kapcsolatos problémákkal, és elmagyarázza, hogyan minimalizálható a szemétgyűjtés hatása az alkalmazásokra. Minden probléma olyan eljárásokra mutató hivatkozásokkal rendelkezik, amelyekkel kivizsgálhatja a problémákat.

Teljesítményelemzési eszközök

A következő szakaszok ismertetik a memóriahasználattal és a szemétgyűjtési problémákkal kapcsolatos problémák kivizsgálására rendelkezésre álló eszközöket. A cikk későbbi részében ismertetett eljárások ezekre az eszközökre vonatkoznak.

Memóriateljesítmény-számlálók

Teljesítményszámlálókkal teljesítményadatokat gyűjthet. Útmutatásért lásd : Runtime Profiling. A teljesítményszámlálók .NET CLR memóriakategóriája a .NET teljesítményszámlálóiban leírtak szerint információt nyújt a szemétgyűjtőről.

Hibakeresés az SOS használatával

A Windows Hibakereső (WinDbg) használatával megvizsgálhatja a felügyelt halom objektumait.

A WinDbg telepítéséhez telepítse a Windows hibakeresési eszközeit a Windowshoz készült hibakeresési eszközök letöltési oldaláról.

Szemétgyűjtési ETW-események

A Windows eseménykövetése (ETW) egy nyomkövetési rendszer, amely kiegészíti a .NET által biztosított profilkészítési és hibakeresési támogatást. A 4. .NET-keretrendszer kezdve a szemétgyűjtési ETW-események hasznos információkat rögzítenek a felügyelt halom statisztikai szempontból történő elemzéséhez. A szemétgyűjtés során létrejönő esemény például GCStart_V1 a következő információkat adja meg:

  • Az objektumok melyik generációját gyűjti össze a rendszer.
  • Mi váltotta ki a szemétgyűjtést.
  • A szemétgyűjtés típusa (egyidejű vagy nem egyidejű).

Az ETW eseménynaplózása hatékony, és nem fedi el a szemétgyűjtéssel kapcsolatos teljesítményproblémát. A folyamat képes saját eseményeket biztosítani az ETW-eseményekkel együtt. Naplózva az alkalmazás eseményei és a szemétgyűjtési események korrelálhatók annak meghatározásához, hogy hogyan és mikor fordulnak elő halomproblémák. Egy kiszolgálóalkalmazás például eseményeket biztosíthat egy ügyfélkérés elején és végén.

A Profilkészítési API

A közös nyelvi futtatókörnyezet (CLR) profilkészítési felületei részletes információkat nyújtanak a szemétgyűjtés során érintett objektumokról. A profilkészítők értesítést kaphatnak a szemétgyűjtés elindulásáról és befejezéséről. Jelentéseket tud nyújtani a felügyelt halom objektumairól, beleértve az egyes generációk objektumainak azonosítását is. További információ: Profilkészítés áttekintése.

A profilkészítők átfogó információkat nyújthatnak. Az összetett profilkészítők azonban módosíthatják az alkalmazások viselkedését.

Alkalmazástartomány erőforrás-monitorozása

A 4. .NET-keretrendszer kezdve az alkalmazástartomány erőforrás-monitorozása (ARM) lehetővé teszi, hogy a gazdagépek alkalmazástartományonként monitorozzák a processzor- és memóriahasználatot. További információ: Application Domain Resource Monitoring.

Teljesítményproblémák elhárítása

Az első lépés annak meghatározása, hogy a probléma valójában szemétgyűjtés-e. Ha azt állapítja meg, hogy igen, válassza az alábbi listából a probléma elhárításához.

Probléma: Memóriakivétel van kibocsátva

A felügyeltek OutOfMemoryException esetében két jogos eset áll fenn:

  • Elfogy a virtuális memória.

    A szemétgyűjtő előre meghatározott méretű szegmensekben foglalja le a memóriát a rendszerből. Ha egy foglaláshoz további szegmensre van szükség, de a folyamat virtuális memóriájában nincs egybefüggő szabad blokk, a felügyelt halom lefoglalása sikertelen lesz.

  • Nincs elég fizikai memória a lefoglaláshoz.

Teljesítményellenőrzések
Határozza meg, hogy a memóriakivétel felügyelt-e.
Határozza meg, hogy mennyi virtuális memória foglalható le.
Határozza meg, hogy van-e elegendő fizikai memória.

Ha úgy ítéli meg, hogy a kivétel nem jogszerű, forduljon a Microsoft ügyfélszolgálatához az alábbi információkkal:

  • A felügyelt memóriakivétellel rendelkező verem.
  • Teljes memóriakép.
  • Azok az adatok, amelyek igazolják, hogy ez nem memóriakivétel, beleértve azokat az adatokat is, amelyek azt mutatják, hogy a virtuális vagy a fizikai memória nem jelent problémát.

Probléma: A folyamat túl sok memóriát használ

Gyakori feltételezés, hogy a Windows Feladatkezelő Teljesítmény lapján megjelenő memóriahasználat jelezheti, ha túl sok memória van használatban. Ez a megjelenítés azonban a munkakészletre vonatkozik; nem ad meg információt a virtuális memória használatáról.

Ha megállapítja, hogy a problémát a felügyelt halom okozza, a minták meghatározásához meg kell mérnie a felügyelt halomot.

Ha megállapítja, hogy a problémát nem a felügyelt halom okozza, natív hibakeresést kell használnia.

Teljesítményellenőrzések
Határozza meg, hogy mennyi virtuális memória foglalható le.
Határozza meg, hogy a felügyelt halom mekkora memóriát véglegesítse.
Határozza meg, hogy a felügyelt halom mennyi memóriát foglal le.
Nagy objektumok meghatározása a 2. generációban.
Objektumokra mutató hivatkozások meghatározása.

Probléma: A szemétgyűjtő nem vonja vissza elég gyorsan az objektumokat

Ha úgy tűnik, hogy az objektumok nem a várt módon lesznek visszakövetelve a szemétgyűjtéshez, meg kell állapítania, hogy vannak-e erős hivatkozások ezekre az objektumokra.

Ezt a problémát akkor is tapasztalhatja, ha nem történt szemétgyűjtés a halott objektumot tartalmazó generáció számára, ami azt jelzi, hogy a halott objektum véglegesítője nem lett futtatva. Ez például akkor lehetséges, ha egyszálas lakásalkalmazást (STA) futtat, és a véglegesítő üzenetsort kiszolgáló szál nem hívható be.

Teljesítményellenőrzések
Ellenőrizze az objektumokra mutató hivatkozásokat.
Annak megállapítása, hogy a véglegesítő futtatva van-e.
Határozza meg, hogy vannak-e véglegesítésre váró objektumok.

Probléma: A felügyelt halom túl töredezett

A töredezettségi szintet a rendszer a szabad terület és a teljes lefoglalt memória arányával számítja ki a generáció számára. A 2. generáció esetében a töredezettség elfogadható szintje legfeljebb 20%. Mivel a 2. generáció nagyon nagy lehet, a töredezettség aránya fontosabb, mint az abszolút érték.

A 0. generációs szabad terület használata nem jelent problémát, mert ez az a generáció, ahol új objektumok vannak lefoglalva.

A töredezettség mindig a nagy objektum halomban fordul elő, mert nem tömöríti. A szomszédos szabad objektumok természetesen egyetlen térbe vannak összecsukva a nagy méretű objektumfoglalási kérelmek kielégítése érdekében.

A töredezettség problémát okozhat az 1. és a 2. generációban. Ha ezek a generációk nagy mennyiségű szabad területtel rendelkeznek a szemétgyűjtés után, előfordulhat, hogy az alkalmazás objektumhasználata módosításra szorul, és érdemes megfontolni a hosszú távú objektumok élettartamának újraértékelését.

Az objektumok túlzott rögzítése növelheti a töredezettségeket. Ha a töredezettség magas, túl sok objektum rögzíthető.

Ha a virtuális memória töredezettsége megakadályozza, hogy a szemétgyűjtő szegmenseket adjon hozzá, az okok a következők lehetnek:

  • Sok kis szerelvények gyakori be- és kirakodása.

  • Ha nem felügyelt kóddal működik, túl sok hivatkozás van a COM-objektumokra.

  • Nagy átmeneti objektumok létrehozása, amelyek miatt a nagy objektum halom gyakran foglal le és szabadít fel halomszegmenseket.

    A CLR üzemeltetése során egy alkalmazás kérheti, hogy a szemétgyűjtő megtartsa a szegmenseit. Ez csökkenti a szegmensfoglalások gyakoriságát. Ezt a STARTUP_FLAGS Enumerálás STARTUP_HOARD_GC_VM jelölőjének használatával lehet elvégezni.

Teljesítményellenőrzések
Határozza meg a felügyelt halom szabad területének mennyiségét.
Határozza meg a rögzített objektumok számát.

Ha úgy véli, hogy a töredezettségnek nincs jogos oka, forduljon a Microsoft ügyfélszolgálatához és ügyfélszolgálatához.

Probléma: A szemétgyűjtés szüneteltetése túl hosszú

A szemétgyűjtés valós időben működik, ezért az alkalmazásnak képesnek kell lennie némi szünetet elviselni. A helyreállítható valós idejű műveletek egyik feltétele, hogy a műveletek 95%-ának időben kell befejeződnie.

Egyidejű szemétgyűjtés esetén a felügyelt szálak futtathatók a gyűjtemény során, ami azt jelenti, hogy a szüneteltetések nagyon minimálisak.

A rövid ideig tartó szemétgyűjtés (0. és 1. generáció) csak néhány ezredmásodpercig tart, ezért a szüneteltetések csökkentése általában nem megvalósítható. A 2. generációs gyűjtemények szüneteit azonban csökkentheti úgy, hogy módosítja az alkalmazás általi foglalási kérelmek mintáját.

Egy másik, pontosabb módszer a szemétgyűjtési ETW-események használata. A gyűjtemények időzítését úgy találja meg, hogy hozzáadja az események sorozatához tartozó időbélyeg-különbségeket. A teljes gyűjteménysorozat magában foglalja a végrehajtó motor felfüggesztését, magát a szemétgyűjtést és a végrehajtó motor újraindítását.

A Szemétgyűjtési értesítések segítségével megállapíthatja, hogy egy kiszolgáló 2. generációs gyűjteményt fog-e használni, és hogy a kérések másik kiszolgálóra való átirányítása enyhítheti-e a szüneteltetésekkel kapcsolatos problémákat.

Teljesítményellenőrzések
Határozza meg a szemétgyűjtés időtartamát.
Határozza meg, hogy mi okozta a szemétgyűjtést.

Probléma: A 0. generáció túl nagy

A 0. generáció valószínűleg nagyobb számú objektummal rendelkezik egy 64 bites rendszeren, különösen akkor, ha a munkaállomás szemétgyűjtése helyett kiszolgálói szemétgyűjtést használ. Ennek az az oka, hogy a 0. generációs szemétgyűjtés aktiválásának küszöbértéke magasabb ezekben a környezetekben, és a 0. generációs gyűjtemények sokkal nagyobbak lehetnek. A teljesítmény akkor javul, ha egy alkalmazás több memóriát foglal le a szemétgyűjtés aktiválása előtt.

Probléma: A processzorhasználat a szemétgyűjtés során túl magas

A cpu-használat magas lesz a szemétgyűjtés során. Ha jelentős mennyiségű folyamatidőt töltenek egy szemétgyűjtésben, a gyűjtemények száma túl gyakori, vagy a gyűjtemény túl hosszú ideig tart. A felügyelt halom objektumainak megnövekedett foglalási aránya miatt gyakrabban fordul elő szemétgyűjtés. A foglalási arány csökkentése csökkenti a szemétgyűjtés gyakoriságát.

A foglalási arányokat a Allocated Bytes/second teljesítményszámlálóval figyelheti. További információ: Teljesítményszámlálók a .NET-ben.

A gyűjtemény időtartama elsősorban azon objektumok számának tényezője, amelyek a lefoglalás után is megmaradnak. A szemétgyűjtőnek nagy mennyiségű memórián kell átmennie, ha sok objektumot kell összegyűjteni. A túlélők tömörítése időigényes munka. Annak megállapításához, hogy hány objektumot kezeltek a gyűjtemény során, állítson be töréspontot a hibakeresőben egy adott generáció szemétgyűjtésének végén.

Teljesítményellenőrzések
Állapítsa meg, hogy a magas processzorhasználatot a szemétgyűjtés okozza-e.
Állítson be egy töréspontot a szemétgyűjtés végén.

Hibaelhárítási irányelvek

Ez a szakasz azokat az irányelveket ismerteti, amelyeket érdemes megfontolnia a vizsgálatok megkezdésekor.

Munkaállomás vagy kiszolgáló szemétgyűjtése

Állapítsa meg, hogy a megfelelő típusú szemétgyűjtést használja-e. Ha az alkalmazás több szálat és objektumpéldányt használ, a munkaállomás szemétgyűjtése helyett használjon kiszolgálói szemétgyűjtést. A kiszolgálói szemétgyűjtés több szálon működik, míg a munkaállomás szemétgyűjtéséhez több alkalmazáspéldányra van szükség a saját szemétgyűjtési szálak futtatásához és a processzoridőért való versengéshez.

Az alacsony terhelésű és a háttérben ritkán elvégzendő feladatokat (például egy szolgáltatást) használó alkalmazások használhatják a munkaállomás szemétgyűjtését, ha az egyidejű szemétgyűjtés le van tiltva.

Mikor kell mérni a felügyelt halomméretet?

Ha nem használ profilkészítőt, konzisztens mérési mintát kell létrehoznia a teljesítményproblémák hatékony diagnosztizálásához. Az ütemezés kialakításához vegye figyelembe az alábbi szempontokat:

  • Ha a 2. generációs szemétgyűjtés után mér, a teljes felügyelt halom szemétmentes lesz (holt objektumok).
  • Ha közvetlenül a 0. generációs szemétgyűjtés után mér, az 1. és a 2. generáció objektumai még nem lesznek összegyűjtve.
  • Ha közvetlenül a szemétgyűjtés előtt mér, a lehető legtöbb lefoglalást fogja mérni a szemétgyűjtés megkezdése előtt.
  • A szemétgyűjtés során történő mérés problematikus, mert a szemétgyűjtő adatstruktúrái nincsenek érvényes állapotban a bejáráshoz, és nem biztos, hogy teljes eredményt adnak. Ez az elvárt működés.
  • Ha a munkaállomás szemétgyűjtését egyidejű szemétgyűjtéssel használja, a visszanyert objektumok nem lesznek tömörítve, így a halom mérete azonos vagy nagyobb lehet (a töredezettség nagyobbnak tűnhet).
  • A 2. generáció egyidejű szemétgyűjtése késik, ha a fizikai memória terhelése túl magas.

Az alábbi eljárás bemutatja, hogyan állíthat be töréspontot a felügyelt halom méréséhez.

Töréspont beállítása a szemétgyűjtés végén

  • Az SOS hibakereső bővítményt tartalmazó WinDbg-ben adja meg a következő parancsot:

    bp mscorwks!WKS::GCHeap::RestartEE "j (dwo(mscorwks!WKS::GCHeap::GcCondemnedGeneration)==2) 'kb';'g'"

    Állítsa a GcCondemnedGeneration kívánt generációra. Ehhez a parancshoz privát szimbólumok szükségesek.

    Ez a parancs megszakítja RestartEE a 2. generációs objektumok szemétgyűjtéshez való visszaigénylését.

    A kiszolgáló szemétgyűjtésében csak egy szál hívja meg a szálakat RestartEE, így a töréspont csak egyszer fordul elő a 2. generációs szemétgyűjtés során.

Teljesítményellenőrzési eljárások

Ez a szakasz a teljesítményproblémák okának elkülönítésére vonatkozó alábbi eljárásokat ismerteti:

Annak megállapítása, hogy a problémát a szemétgyűjtés okozza-e

  • Vizsgálja meg a következő két memóriateljesítmény-számlálót:

    • %Time in GC. Megjeleníti a legutóbbi szemétgyűjtési ciklus után a szemétgyűjtés végrehajtásával töltött eltelt idő százalékos arányát. Ezzel a számlálóval megállapíthatja, hogy a szemétgyűjtő túl sok időt tölt-e a felügyelt halomterület rendelkezésre állásához. Ha a szemétgyűjtésben töltött idő viszonylag alacsony, az erőforrás-problémát jelezhet a felügyelt halomon kívül. Előfordulhat, hogy ez a számláló nem pontos, ha egyidejű vagy háttérbeli szemétgyűjtésről van szó.

    • # Véglegesített bájtok száma. Megjeleníti a szemétgyűjtő által jelenleg lekötött virtuális memória mennyiségét. Ezzel a számlálóval megállapíthatja, hogy a szemétgyűjtő által felhasznált memória a memória túlzott része-e, amelyet az alkalmazás használ.

    A memóriateljesítmény-számlálók többsége az egyes szemétgyűjtések végén frissül. Ezért előfordulhat, hogy ezek nem tükrözik azokat a jelenlegi feltételeket, amelyekről információt szeretne kapni.

Annak meghatározása, hogy a memóriakivétel kezelése történik-e

  1. Az SOS hibakeresőbővítménnyel rendelkező WinDbg vagy Visual Studio hibakeresőben adja meg a nyomtatási kivétel (pe) parancsot:

    !pe

    Ha a kivétel kezelése történik, OutOfMemoryException akkor a rendszer kivételtípusként jelenik meg, ahogyan az alábbi példában is látható.

    Exception object: 39594518
    Exception type: System.OutOfMemoryException
    Message: <none>
    InnerException: <none>
    StackTrace (generated):
    
  2. Ha a kimenet nem ad meg kivételt, meg kell határoznia, hogy melyik szálból származik a memóriakivétel. Adja meg a következő parancsot a hibakeresőben az összes szál megjelenítéséhez a hívásveremekkel:

    ~\*kb

    A kivételhívásokat tartalmazó vermet tartalmazó szálat az RaiseTheException argumentum jelöli. Ez a felügyelt kivételobjektum.

    28adfb44 7923918f 5b61f2b4 00000000 5b61f2b4 mscorwks!RaiseTheException+0xa0
    
  3. A beágyazott kivételeket az alábbi paranccsal teheti ki.

    !pe -nested

    Ha nem talál kivételeket, a memóriakivétel nem felügyelt kódból származik.

Annak meghatározása, hogy mennyi virtuális memória foglalható le

  • Az SOS hibakereső bővítményt tartalmazó WinDbg-ben adja meg a következő parancsot a legnagyobb ingyenes régió lekéréséhez:

    !address -summary

    A legnagyobb szabad régió az alábbi kimenetben látható módon jelenik meg.

    Largest free region: Base 54000000 - Size 0003A980
    

    Ebben a példában a legnagyobb szabad régió mérete körülbelül 24000 KB (hexadecimális 3A980). Ez a régió sokkal kisebb, mint amire a szemétgyűjtőnek szüksége van egy szegmenshez.

    -Vagy-

  • Használja a vmstat következő parancsot:

    !vmstat

    A legnagyobb szabad régió a LEGNAGYOBB oszlop legnagyobb értéke, ahogy az az alábbi kimenetben is látható.

    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
    

Annak meghatározása, hogy van-e elegendő fizikai memória

  1. Indítsa el a Windows Feladatkezelőt.

  2. Performance A lapon tekintse meg a véglegesített értéket. (A Windows 7-ben tekintse Commit (KB) meg a System group.)

    Ha a Total rendszer a közelben Limitvan, akkor kevés a fizikai memória.

Annak meghatározása, hogy a felügyelt halom mennyi memóriát véglegesített

  • # Total committed bytes A memóriateljesítmény-számlálóval lekérheti a felügyelt halom által véglegesített bájtok számát. A szemétgyűjtő szükség szerint véglegesíti az adattömböket egy szegmensen, nem egyszerre.

    Feljegyzés

    Ne használja a # Bytes in all Heaps teljesítményszámlálót, mert nem a felügyelt halom tényleges memóriahasználatát jelöli. Egy generáció mérete ebben az értékben szerepel, és valójában a küszöbértéke, vagyis az a méret, amely szemétgyűjtést indukál, ha a generáció tele van objektumokkal. Ezért ez az érték általában nulla.

Annak meghatározása, hogy a felügyelt halom mennyi memóriát foglal le

  • Használja a # Total reserved bytes memóriateljesítmény-számlálót.

    A szemétgyűjtő szegmensekben foglalja le a memóriát, és a parancs használatával meghatározhatja, hogy hol kezdődik egy eeheap szegmens.

    Fontos

    Bár meghatározhatja, hogy a szemétgyűjtő mennyi memóriát foglal le az egyes szegmensekhez, a szegmens mérete implementációspecifikus, és bármikor változhat, beleértve az időszakos frissítéseket is. Az alkalmazásnak soha nem szabad feltételezéseket feltételeznie egy adott szegmens méretéről vagy attól függenie, és nem is próbálja meg konfigurálni a szegmensfoglalásokhoz rendelkezésre álló memória mennyiségét.

  • Az SOS hibakereső bővítményt tartalmazó WinDbg- vagy Visual Studio-hibakeresőben adja meg a következő parancsot:

    !eeheap -gc

    Az eredmény a következő.

    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)
    

    A "szegmens" által megjelölt címek a szegmensek kezdőcímei.

Nagy objektumok meghatározása a 2. generációban

  • Az SOS hibakereső bővítményt tartalmazó WinDbg- vagy Visual Studio-hibakeresőben adja meg a következő parancsot:

    !dumpheap –stat

    Ha a felügyelt halom nagy, dumpheap eltarthat egy ideig.

    Elkezdheti az elemzést a kimenet utolsó néhány sorából, mert a legtöbb helyet használó objektumokat listázzák. Példa:

    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
    

    Az utolsó felsorolt objektum egy sztring, és a legtöbb helyet foglalja el. Megvizsgálhatja az alkalmazást, hogy lássa, hogyan optimalizálhatók a sztringobjektumok. A 150 és 200 bájt közötti sztringek megtekintéséhez írja be a következőket:

    !dumpheap -type System.String -min 150 -max 200

    Az eredményekre a következő példa látható.

    Address  MT           Size  Gen
    1875d2c0 790fa3e0      152    2 System.String HighlightNullStyle_Blotter_PendingOrder-11_Blotter_PendingOrder-11
    …
    

    Az azonosítók sztring helyett egész szám használata hatékonyabb lehet. Ha ugyanazt a sztringet több ezer alkalommal ismétli meg, fontolja meg a sztringek közötti internálást. A sztringek közötti internálással kapcsolatos további információkért tekintse meg a metódus referenciatémakörét String.Intern .

Objektumokra mutató hivatkozások meghatározása

  • Az SOS hibakereső bővítményt tartalmazó WinDbg-ben adja meg az alábbi parancsot az objektumokra mutató hivatkozások listázásához:

    !gcroot

    -Vagy-

  • Egy adott objektum hivatkozásainak meghatározásához adja meg a címet:

    !gcroot 1c37b2ac

    A veremeken található gyökerek hamis pozitívak lehetnek. További információkért használja a parancsot !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
    

    A gcroot parancs végrehajtása hosszú időt vehet igénybe. A szemétgyűjtés által nem visszanyert objektumok élő objektumok. Ez azt jelenti, hogy néhány gyökér közvetlenül vagy közvetve az objektumhoz kötődik, ezért gcroot az elérési út adatait vissza kell adnia az objektumnak. Meg kell vizsgálnia a visszaadott gráfokat, és meg kell vizsgálnia, hogy miért hivatkoznak még ezekre az objektumokra.

Annak megállapítása, hogy a véglegesítő futtatása megtörtént-e

  • Futtasson egy tesztprogramot, amely a következő kódot tartalmazza:

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    

    Ha a teszt megoldja a problémát, ez azt jelenti, hogy a szemétgyűjtő nem igényelt vissza objektumokat, mert az objektumok véglegesítőit felfüggesztették. A GC.WaitForPendingFinalizers módszer lehetővé teszi, hogy a véglegesítők elvégezzék a feladataikat, és kijavítsák a problémát.

Annak meghatározása, hogy vannak-e véglegesítésre váró objektumok

  1. Az SOS hibakereső bővítményt tartalmazó WinDbg- vagy Visual Studio-hibakeresőben adja meg a következő parancsot:

    !finalizequeue

    Tekintse meg a véglegesítésre kész objektumok számát. Ha a szám magas, meg kell vizsgálnia, hogy ezek a véglegesítők egyáltalán miért nem tudnak előrehaladni, vagy nem tudnak elég gyorsan haladni.

  2. A szálak kimenetének lekéréséhez írja be a következő parancsot:

    !threads -special

    Ez a parancs a következőhöz hasonló kimenetet biztosít.

       OSID     Special thread type
    2    cd0    DbgHelper
    3    c18    Finalizer
    4    df0    GC SuspendEE
    

    A finalizer szál jelzi, hogy melyik véglegesítő fut éppen, ha van ilyen. Ha egy finalizer-szál nem futtat véglegesítőket, az eseményre vár, hogy elmondja neki, hogy végezze el a munkáját. Az idő nagy részében ebben az állapotban fogja látni a finalizer szálat, mert THREAD_HIGHEST_PRIORITY fut, és a véglegesítők futtatását kell befejeznie, ha vannak ilyenek, nagyon gyorsan.

A felügyelt halom szabad területének meghatározása

  • Az SOS hibakereső bővítményt tartalmazó WinDbg- vagy Visual Studio-hibakeresőben adja meg a következő parancsot:

    !dumpheap -type Free -stat

    Ez a parancs megjeleníti a felügyelt halom összes szabad objektumának teljes méretét, ahogyan az az alábbi példában is látható.

    total 230 objects
    Statistics:
          MT    Count    TotalSize Class Name
    00152b18      230     40958584      Free
    Total 230 objects
    
  • A 0. generáció szabad helyének meghatározásához adja meg a következő parancsot a memóriahasználati információk generációnkénti megadásához:

    !eeheap -gc

    Ez a parancs az alábbihoz hasonló kimenetet jelenít meg. Az utolsó sorban a rövid élettartamú szegmens látható.

    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)
    
  • Számítsa ki a 0. generáció által használt területet:

    ? 49e05d04-0x49521f8c

    Az eredmény a következő. A 0. generáció körülbelül 9 MB.

    Evaluate expression: 9321848 = 008e3d78
    
  • A következő parancs a 0. generációs tartomány szabad területét adja ki:

    !dumpheap -type Free -stat 0x49521f8c 49e05d04

    Az eredmény a következő.

    ------------------------------
    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
    

    Ez a kimenet azt mutatja, hogy a halom 0. generációs része 9 MB területet használ az objektumok számára, és 7 MB szabad. Ez az elemzés bemutatja, hogy a 0. generáció milyen mértékben járul hozzá a töredezettséghez. Ezt a halomhasználatot a teljes összegből kell kivenni a hosszú távú objektumok töredezettségének okaként.

Rögzített objektumok számának meghatározása

  • Az SOS hibakereső bővítményt tartalmazó WinDbg- vagy Visual Studio-hibakeresőben adja meg a következő parancsot:

    !gchandles

    A megjelenített statisztikák tartalmazzák a rögzített fogópontok számát, ahogy az az alábbi példában is látható.

    GC Handle Statistics:
    Strong Handles:      29
    Pinned Handles:      10
    

A szemétgyűjtés időtartamának meghatározása

  • Vizsgálja meg a memóriateljesítmény-számlálót % Time in GC .

    Az érték kiszámítása mintaintervallum-idő alapján történik. Mivel a számlálók az egyes szemétgyűjtések végén frissülnek, az aktuális minta értéke megegyezik az előző mintával, ha az intervallum alatt nem történt gyűjtemény.

    A gyűjtési idő a mintaintervallum és a százalékos érték szorzatával nyerhető ki.

    A következő adatok négy két másodperces mintavételi időközt mutatnak egy 8 másodperces vizsgálathoz. A Gen0, Gen1és Gen2 az oszlopok az adott generációs intervallum végére befejezett szemétgyűjtések teljes számát jelenítik meg.

    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
    

    Ez az információ nem jeleníti meg, hogy mikor történt a szemétgyűjtés, de meghatározhatja az időintervallumban történt szemétgyűjtések számát. A legrosszabb esetet feltételezve a 0. generációs szemétgyűjtés a második intervallum elején, a 11. generációs 0 szemétgyűjtés pedig a harmadik intervallum végén fejeződött be. A tizedik és a tizenegyedik szemétgyűjtés vége közötti idő körülbelül 2 másodperc, a teljesítményszámláló pedig 3%-ot mutat, így a 11. generációs 0 szemétgyűjtés időtartama (2 másodperc * 3% = 60 ms).

    A következő példában öt időköz van.

    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
    

    A második generációs 2 szemétgyűjtés a negyedik intervallumban kezdődött, és az ötödik intervallumban fejeződött be. A legrosszabb esetet feltételezve az utolsó szemétgyűjtés egy 0. generációs gyűjteményre vonatkozik, amely a harmadik intervallum elején fejeződött be, a 2. generációs szemétgyűjtés pedig az ötödik intervallum végén fejeződött be. Ezért a 0. generációs szemétgyűjtés vége és a 2. generációs szemétgyűjtés vége közötti idő 4 másodperc. Mivel a % Time in GC számláló 20%, a 2. generációs szemétgyűjtés maximális időtartama (4 másodperc * 20% = 800 ms).

  • Másik lehetőségként meghatározhatja a szemétgyűjtés hosszát a szemétgyűjtés ETW-eseményeinek használatával, és elemezheti az információkat a szemétgyűjtés időtartamának meghatározásához.

    Az alábbi adatok például olyan eseményütemezést mutatnak, amely nem egyidejű szemétgyűjtés során történt.

    Timestamp    Event name
    513052        GCSuspendEEBegin_V1
    513078        GCSuspendEEEnd
    513090        GCStart_V1
    517890        GCEnd_V1
    517894        GCHeapStats
    517897        GCRestartEEBegin
    517918        GCRestartEEEnd
    

    A felügyelt szál felfüggesztése 26us (GCSuspendEEEndGCSuspendEEBegin_V1) értéket vett igénybe.

    A tényleges szemétgyűjtés 4,8 m ( –GCEnd_V1GCStart_V1).

    A felügyelt szálak folytatása 21us (GCRestartEEEndGCRestartEEBegin) értéket vett igénybe.

    Az alábbi kimenet egy példa a háttérbeli szemétgyűjtésre, és tartalmazza a folyamatot, a szálat és az eseménymezőket. (Nem minden adat jelenik meg.)

    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
    

    A GCStart_V1 42504816 esemény azt jelzi, hogy ez egy háttérbeli szemétgyűjtés, mert az utolsó mező.1 Ez lesz a 102019. számú szemétgyűjtés.

    Az GCStart esemény azért fordul elő, mert a háttérbeli szemétgyűjtés megkezdése előtt rövid ideig szükség van a szemétgyűjtésre. Ez lesz a 102020-ra szóló szemétgyűjtés.

    A 42514170 102020-ra befejeződött a szemétgyűjtés. A felügyelt szálak ezen a ponton újraindulnak. Ez a 4372-s szálon fejeződik be, amely aktiválta ezt a háttérbeli szemétgyűjtést.

    A 4744-ben felfüggesztés történik. Ez az egyetlen alkalom, amikor a háttérbeli szemétgyűjtésnek fel kell függesztenie a felügyelt szálakat. Ez az időtartam körülbelül 99 ms ((63784407-63685394)/1000).

    A GCEnd háttérbeli szemétgyűjtés eseménye 89931423. Ez azt jelenti, hogy a háttérbeli szemétgyűjtés körülbelül 47 másodpercig tartott ((89931423-42504816)/1000).

    Miközben a felügyelt szálak futnak, tetszőleges számú rövid ideig futó szemétgyűjtés jelenik meg.

Annak meghatározása, hogy mi váltott ki szemétgyűjtést

  • Az SOS hibakereső bővítményt tartalmazó WinDbg- vagy Visual Studio-hibakeresőben adja meg a következő parancsot a hívásveremekkel rendelkező összes szál megjelenítéséhez:

    ~*kb

    Ez a parancs az alábbihoz hasonló kimenetet jelenít meg.

    0012f3b0 79ff0bf8 mscorwks!WKS::GCHeap::GarbageCollect
    0012f454 30002894 mscorwks!GCInterface::CollectGeneration+0xa4
    0012f490 79fa22bd fragment_ni!request.Main(System.String[])+0x48
    

    Ha a szemétgyűjtést az operációs rendszer alacsony memória-értesítése okozta, a hívásverem hasonló, azzal a különbségtel, hogy a szál a véglegesítő szál. A finalizer szál aszinkron alacsony memória-értesítést kap, és indukálja a szemétgyűjtést.

    Ha a szemétgyűjtést memóriafoglalás okozta, a verem a következőképpen jelenik meg:

    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
    

    A just-in-time segítő (JIT_New*) végül meghívja GCHeap::GarbageCollectGeneration. Ha megállapítja, hogy a 2. generációs szemétgyűjtéseket foglalások okozzák, meg kell határoznia, hogy a 2. generációs szemétgyűjtés mely objektumokat gyűjti össze, és hogyan kerülheti el őket. Ez azt jelzi, hogy mi a különbség a 2. generációs szemétgyűjtés kezdete és vége, valamint a 2. generációs gyűjteményt okozó objektumok között.

    Írja be például a következő parancsot a hibakeresőbe a 2. generációs gyűjtemény elejének megjelenítéséhez:

    !dumpheap –stat

    Példakimenet (a legnagyobb helyet használó objektumok rövidített megjelenítése):

    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
    

    Ismételje meg a parancsot a 2. generáció végén:

    !dumpheap –stat

    Példakimenet (a legnagyobb helyet használó objektumok rövidített megjelenítése):

    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
    

    Az double[] objektumok eltűntek a kimenet végéről, ami azt jelenti, hogy összegyűjtötték őket. Ezek az objektumok körülbelül 70 MB-ot számlálnak. A többi objektum nem sokat változott. Ezért ezek az double[] objektumok voltak az oka ennek a 2. generációs szemétgyűjtésnek. A következő lépés annak meghatározása, hogy miért vannak ott az double[] objektumok, és miért haltak meg. Megkérdezheti a kód fejlesztőjét, hogy honnan származnak ezek az objektumok, vagy használhatja a gcroot parancsot.

Annak megállapítása, hogy a magas processzorhasználatot a szemétgyűjtés okozza-e

  • Korrelálja a % Time in GC memóriateljesítmény-számláló értékét a folyamatidővel.

    Ha az érték a % Time in GC folyamatidővel egy időben emelkedik, a szemétgyűjtés magas processzorhasználatot okoz. Ellenkező esetben profilozza az alkalmazást, hogy megtudja, hol fordul elő a magas kihasználtság.

Lásd még