Heap-snapshots opnemen, Heap-snapshots opnemen

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

Leer hoe u heap-snapshots kunt opnemen met Geheugen > Profielen > Heap-snapshot en hoe u geheugenlekken kunt opsporen.

De heap profiler toont de geheugenverdeling door de JavaScript-objecten van uw pagina en gerelateerde DOM-knooppunten. Gebruik het om JS-heap-snapshots te maken, geheugengrafieken te analyseren, snapshots te vergelijken en geheugenlekken te vinden. Zie Objecten die de structuur behouden voor meer informatie.

Een momentopname maken

Een heap-snapshot maken:

  1. Op een pagina die u wilt profileren, opent u DevTools en navigeert u naar het paneel Geheugen .
  2. Selecteer het radio_button_checked Heap snapshot- profileringstype, selecteer vervolgens een JavaScript VM-instantie en klik op Momentopname maken .

Een geselecteerd profileringstype en JavaScript VM-instantie.

Wanneer het paneel Geheugen de momentopname laadt en parseert, wordt de totale grootte van bereikbare JavaScript-objecten weergegeven onder de titel van de momentopname in de sectie HEAP SNAPSHOTS .

De totale grootte van bereikbare objecten.

Snapshots tonen alleen de objecten uit de geheugengrafiek die bereikbaar zijn vanuit het globale object. Het maken van een momentopname begint altijd met het verzamelen van afval.

Een heap-momentopname van verspreide Item-objecten.

Duidelijke momentopnamen

Om alle snapshots te verwijderen, klikt u op Blok Alle profielen wissen :

Wis alle profielen.

Bekijk momentopnamen

Om snapshots vanuit verschillende perspectieven voor verschillende doeleinden te bekijken, selecteert u een van de weergaven in het vervolgkeuzemenu bovenaan:

Weergave Inhoud Doel
Samenvatting Objecten gegroepeerd op constructornamen. Gebruik het om objecten en hun geheugengebruik op te sporen op basis van type. Handig voor het opsporen van DOM-lekken .
Vergelijking Verschillen tussen twee momentopnamen. Gebruik het om twee (of meer) snapshots te vergelijken, voor en na een operatie. Bevestig de aanwezigheid en oorzaak van een geheugenlek door de delta in het vrijgemaakte geheugen en het aantal referenties te inspecteren.
Insluiting Hoop inhoud Biedt een beter zicht op de objectstructuur en helpt bij het analyseren van objecten waarnaar wordt verwezen in de globale naamruimte (venster) om te ontdekken wat ze in de buurt houdt. Gebruik het om afsluitingen te analyseren en op een laag niveau in uw objecten te duiken.
Statistieken Cirkeldiagram van geheugentoewijzing Bekijk de reële grootte van geheugenonderdelen die zijn toegewezen aan code, tekenreeksen, JS-arrays, getypte arrays en systeemobjecten.

De Samenvattingsweergave geselecteerd in het vervolgkeuzemenu bovenaan.

Samenvatting weergave

In eerste instantie wordt er een heap-momentopname geopend in de overzichtsweergave , waarin constructors in een kolom worden vermeld. U kunt constructors uitvouwen om de objecten te zien die ze hebben geïnstantieerd.

De Samenvatting-weergave met een uitgebreide constructor.

Om irrelevante constructors eruit te filteren, typt u een naam die u wilt inspecteren in het Klassefilter bovenaan de Samenvattingsweergave .

De cijfers naast de constructornamen geven het totale aantal objecten aan dat met de constructor is gemaakt. In de samenvattingsweergave worden ook de volgende kolommen weergegeven:

  • Afstand toont de afstand tot de wortel met behulp van het kortste eenvoudige pad van knooppunten.
  • Ondiep formaat toont de som van de ondiepe afmetingen van alle objecten die door een bepaalde constructor zijn gemaakt. De ondiepe grootte is de grootte van het geheugen dat door een object zelf wordt vastgehouden. Over het algemeen hebben arrays en strings grotere ondiepe afmetingen. Zie ook Objectgroottes .
  • Ingehouden grootte toont de maximaal behouden grootte voor dezelfde set objecten. De behouden grootte is de grootte van het geheugen dat u kunt vrijmaken door een object te verwijderen en de afhankelijke objecten ervan niet langer bereikbaar te maken. Zie ook Objectgroottes .

Wanneer u een constructor uitvouwt, toont de overzichtsweergave alle exemplaren ervan. Elke instantie krijgt een uitsplitsing van de ondiepe en behouden afmetingen in de overeenkomstige kolommen. Het getal na het @ -teken is de unieke ID van het object. Hiermee kunt u heap-snapshots per object vergelijken.

Speciale vermeldingen in Samenvatting

Naast het groeperen op constructors, groepeert de Samenvattingsweergave ook objecten op:

  • Ingebouwde functies zoals Array of Object .
  • Functies die u in uw code hebt gedefinieerd.
  • Speciale categorieën die niet op constructors zijn gebaseerd.

Inzendingen voor constructeurs.

(array)

Deze categorie bevat verschillende interne array-achtige objecten die niet direct overeenkomen met objecten die zichtbaar zijn in JavaScript.

De inhoud van JavaScript Array objecten wordt bijvoorbeeld opgeslagen in een secundair intern object met de naam (object elements)[] , zodat het formaat gemakkelijker kan worden aangepast. Op dezelfde manier worden de benoemde eigenschappen in JavaScript-objecten vaak opgeslagen in secundaire interne objecten met de naam (object properties)[] die ook worden vermeld in de categorie (array) .

(compiled code)

Deze categorie bevat interne gegevens die V8 nodig heeft zodat functies kunnen worden uitgevoerd die zijn gedefinieerd door JavaScript of WebAssembly. Elke functie kan op verschillende manieren worden weergegeven, van klein en langzaam tot groot en snel.

V8 beheert automatisch het geheugengebruik in deze categorie. Als een functie vele malen wordt uitgevoerd, gebruikt V8 meer geheugen voor die functie, zodat deze sneller kan worden uitgevoerd. Als een functie al een tijdje niet is uitgevoerd, kan V8 de interne gegevens voor die functie wissen.

(concatenated string)

Wanneer V8 twee strings aaneenschakelt, zoals met de JavaScript + operator, kan het ervoor kiezen om het resultaat intern weer te geven als een "aaneengeschakelde string", ook wel bekend als de Rope- datastructuur.

In plaats van alle karakters van de twee bronstrings naar een nieuwe string te kopiëren, wijst V8 een klein object toe met interne velden genaamd first en second , die naar de twee bronstrings verwijzen. Hierdoor kan V8 tijd en geheugen besparen. Vanuit het perspectief van JavaScript-code zijn dit gewoon normale tekenreeksen en gedragen ze zich als elke andere tekenreeks.

InternalNode

Deze categorie vertegenwoordigt objecten die buiten V8 zijn toegewezen, zoals C++-objecten gedefinieerd door Blink .

Om C++-klassenamen te zien, gebruikt u Chrome for Testing en doet u het volgende:

  1. Open DevTools en schakel instellingen in Instellingen > Experimenten > check_box Optie weergeven om internals bloot te leggen in heap-snapshots .
  2. Open het paneel Geheugen , selecteer radio_button_checked Heap snapshot en schakel check_box Expose internals in (bevat aanvullende implementatiespecifieke details) .
  3. Reproduceer het probleem waardoor de InternalNode veel geheugen vasthield.
  4. Maak een heap-snapshot. In deze momentopname hebben objecten C++-klassenamen in plaats van InternalNode .
(object shape)

Zoals beschreven in Snelle eigenschappen in V8 , volgt V8 verborgen klassen (of vormen ) zodat meerdere objecten met dezelfde eigenschappen in dezelfde volgorde efficiënt kunnen worden weergegeven. Deze categorie bevat de verborgen klassen, genaamd system / Map (niet gerelateerd aan JavaScript Map ), en gerelateerde gegevens.

(sliced string)

Wanneer V8 een substring moet gebruiken, zoals wanneer JavaScript-code String.prototype.substring() aanroept, kan V8 ervoor kiezen om een ​​gesegmenteerd stringobject toe te wijzen in plaats van alle relevante tekens uit de originele string te kopiëren. Dit nieuwe object bevat een verwijzing naar de originele string en beschrijft welk bereik van tekens uit de originele string moet worden gebruikt.

Vanuit het perspectief van JavaScript-code zijn dit gewoon normale tekenreeksen en gedragen ze zich als elke andere tekenreeks. Als een gesegmenteerde string veel geheugen vasthoudt, heeft het programma mogelijk probleem 2869 geactiveerd en kan het baat hebben bij het nemen van doelbewuste stappen om de gesegmenteerde string "af te vlakken".

system / Context

Interne objecten van het type system / Context bevatten lokale variabelen van een afsluiting : een JavaScript-scope waartoe een geneste functie toegang heeft.

Elke functie-instantie bevat een interne verwijzing naar de Context waarin deze wordt uitgevoerd, zodat deze toegang heeft tot die variabelen. Hoewel Context objecten niet direct zichtbaar zijn vanuit JavaScript, heeft u er wel directe controle over.

(system)

Deze categorie bevat verschillende interne objecten die (nog) niet op een betekenisvollere manier zijn gecategoriseerd.

Vergelijkingsweergave

In de vergelijkingsweergave kunt u gelekte objecten vinden door meerdere snapshots met elkaar te vergelijken. Als u bijvoorbeeld een actie uitvoert en deze ongedaan maakt, zoals het openen en sluiten van een document, mogen er geen extra objecten achterblijven.

Om te verifiëren dat een bepaalde bewerking geen lekken veroorzaakt:

  1. Maak een heap-snapshot voordat u een bewerking uitvoert.
  2. Voer een bewerking uit. Dat wil zeggen: interactie met een pagina op een manier waarvan u denkt dat deze een lek veroorzaakt.
  3. Voer een omgekeerde handeling uit. Dat wil zeggen, voer de tegenovergestelde interactie uit en herhaal deze een paar keer.
  4. Maak een tweede heap-snapshot en wijzig de weergave in Vergelijking , waarbij u deze vergelijkt met Snapshot 1 .

De vergelijkingsweergave toont het verschil tussen twee momentopnamen. Bij het uitvouwen van een totaalinvoer worden toegevoegde en verwijderde objectinstanties weergegeven:

Vergelijkbaar met momentopname 1.

Insluitingsweergave

De Containment- weergave is een 'vogelperspectief' van de objectstructuur van uw toepassing. Hiermee kunt u in functieafsluitingen kijken, interne VM-objecten observeren die samen uw JavaScript-objecten vormen, en begrijpen hoeveel geheugen uw applicatie op een zeer laag niveau gebruikt.

De weergave biedt verschillende toegangspunten:

  • DOMWindow-objecten . Globale objecten voor JavaScript-code.
  • GC-wortels . GC-roots gebruikt door de garbage collector van de VM. GC-roots kunnen bestaan ​​uit ingebouwde objectkaarten, symbooltabellen, VM-threadstacks, compilatiecaches, handle-scopes en globale handvatten.
  • Inheemse objecten . Browserobjecten worden in de virtuele JavaScript-machine 'gepusht' om automatisering mogelijk te maken, bijvoorbeeld DOM-knooppunten en CSS-regels.

De insluitingsweergave.

Het gedeelte Vasthouders

In het gedeelte Vasthouders onder aan het deelvenster Geheugen worden objecten weergegeven die verwijzen naar het object dat in de weergave is geselecteerd.

Het gedeelte Vasthouders.

In dit voorbeeld wordt de geselecteerde tekenreeks behouden door de x eigenschap van een Item instantie.

Zoek een specifiek object

Om een ​​object in de verzamelde heap te vinden, kunt u zoeken met Ctrl + F en de object-ID invoeren.

Benoem functies om sluitingen te onderscheiden

Het helpt enorm om de functies een naam te geven, zodat je onderscheid kunt maken tussen sluitingen in de momentopname.

De volgende code maakt bijvoorbeeld geen gebruik van benoemde functies:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // this is NOT a named function
    return largeStr;
  };

  return lC;
}

Hoewel dit voorbeeld het volgende doet:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

Benoemde functie in een sluiting.

Ontdek DOM-lekken

De heap profiler heeft de mogelijkheid om bidirectionele afhankelijkheden tussen browser-native objecten (DOM-knooppunten en CSS-regels) en JavaScript-objecten weer te geven. Dit helpt bij het ontdekken van anders onzichtbare lekken die optreden als gevolg van vergeten, losgemaakte DOM-substructuren die rondzweven.

DOM-lekken kunnen groter zijn dan u denkt. Beschouw het volgende voorbeeld. Wanneer wordt het #tree opgehaald?

  var select = document.querySelector;
  var treeRef = select("#tree");
  var leafRef = select("#leaf");
  var body = select("body");

  body.removeChild(treeRef);

  //#tree can't be GC yet due to treeRef
  treeRef = null;

  //#tree can't be GC yet due to indirect
  //reference from leafRef

  leafRef = null;
  //#NOW #tree can be garbage collected

#leaf onderhoudt een verwijzing naar zijn ouder ( parentNode ) en recursief tot aan #tree , dus alleen wanneer leafRef teniet wordt gedaan, is de hele boom onder #tree een kandidaat voor GC.

DOM-subbomen