Rejestruj zrzuty sterty

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

Dowiedz się, jak rejestrować obrazy sterty za pomocą opcji Pamięć > Profile > Obraz sterty, i jak znajdować wycieki pamięci.

Program profilujący sterty pokazuje rozkład pamięci według obiektów JavaScript na Twojej stronie i powiązanych węzłów DOM. Za pomocą tego narzędzia możesz robić zrzuty pamięci podręcznej JS, analizować wykresy pamięci, porównywać zrzuty i wyszukiwać wycieki pamięci. Więcej informacji znajdziesz w artykule Drzewo obiektów.

Zrób zdjęcie

Aby wykonać zrzut sterty:

  1. Na stronie, którą chcesz profilować, otwórz Narzędzia deweloperskie i otwórz panel Pamięć.
  2. Wybierz typ profilowania Zrzut stosu, a następnie wybierz wystąpienie maszyny wirtualnej JavaScript i kliknij Zrób zrzut.

Wybrany typ profilowania i wystąpienie maszyny wirtualnej JavaScript.

Gdy panel Pamięć wczytuje i przetwarza zrzut, pod tytułem zrzutu w sekcji SNAPSHOTS pod tytułem zrzutu ekranu wyświetli się łączny rozmiar osiągalnych obiektów JavaScript.

Łączny rozmiar dostępnych obiektów.

Zrzuty ekranu zawierają tylko obiekty z grafu pamięci, które są dostępne z obiektu globalnego. Tworzenie zrzutu zawsze zaczyna się od usuwania elementów zbędących.

Migawka stosu rozproszonych obiektów Item.

Wyczyść zrzuty

Aby usunąć wszystkie migawki, kliknij Wyczyść wszystkie profile:

Wyczyść wszystkie profile.

Wyświetl zrzuty

Aby sprawdzać migawki z różnych perspektyw i do różnych celów, wybierz jeden z widoków w menu u góry:

Wyświetl Treść Cel
Podsumowanie Obiekty pogrupowane według nazw konstruktorów. Dzięki niemu możesz wyszukiwać obiekty i wykorzystywać ich pamięć na podstawie ich typu. Przydatne do śledzenia wycieków danych w DOM.
Porównanie Różnice między 2 zrzutami Użyj go do porównania co najmniej 2 migawek (przed i po wykonaniu operacji). Aby sprawdzić, czy występuje wyciek pamięci i jaka jest jego przyczyna, sprawdź różnicę w ilości zwolnionej pamięci i liczbie odwołań.
Ograniczenie Zawartość stosu Zapewnia lepszy widok struktury obiektów i pomaga analizować obiekty, do których odwołuje się globalna przestrzeń nazw (okno), aby znaleźć to, co je utrzymuje. Za pomocą tego narzędzia możesz analizować zamknięcia i szczegółowo badać obiekty.
Statystyki Wykres kołowy alokacji pamięci Zobacz względne rozmiary części pamięci przydzielonych do kodu, ciągów znaków, tablic JS, tablic typowych i obiektów systemowych.

Widok Podsumowanie wybrany w menu u góry.

Widok podsumowania

Najpierw w widoku Podsumowanie otworzy się migawka stosu, która w kolumnie zawiera listę konstruktorów. Możesz rozwinąć konstruktory, aby zobaczyć instancje obiektów.

Widok Podsumowanie z rozwiniętym konstruktorem.

Aby odfiltrować nieistotne konstruktory, wpisz nazwę, którą chcesz sprawdzić, w polu Filtr klasy u góry widoku Podsumowanie.

Liczby obok nazw konstruktorów wskazują łączną liczbę obiektów utworzonych za pomocą konstruktora. Widok Podsumowanie zawiera też te kolumny:

  • Odległość pokazuje odległość od węzła źródla, korzystając z najkrótszej prostej ścieżki przez węzły.
  • Shallow size (płytki rozmiar) to suma rozmiarów płytkich wszystkich obiektów utworzonych przez dany konstruktor. Płytki rozmiar to rozmiar pamięci przechowywanej przez sam obiekt. Zwykle tablice i ciągi mają większy rozmiar płytki. Zobacz też Rozmiary obiektów.
  • Zachowywany rozmiar to maksymalny rozmiar przechowywany w ramach tego samego zbioru obiektów. Zatrzymany rozmiar to rozmiar pamięci, który możesz zwolnić, usuwając obiekt i uniemożliwiając dostęp do jego elementów zależnych. Zobacz też Rozmiary obiektów.

Gdy rozwiniesz konstruktor, w widoku Podsumowanie zobaczysz wszystkie jego wystąpienia. Każda instancja ma w odpowiednich kolumnach podział na rozmiary płytkie i zatrzymane. Liczba po znaku @ to unikalny identyfikator obiektu. Umożliwia porównywanie zrzutów stosu na podstawie poszczególnych obiektów.

Filtry konstruktora

Widok Podsumowanie umożliwia filtrowanie konstruktorów na podstawie typowych przypadków niewydajnego wykorzystania pamięci.

Aby użyć tych filtrów, w menu po prawej stronie na pasku działań wybierz jedną z tych opcji:

  • Wszystkie obiekty: wszystkie obiekty zarejestrowane przez bieżący zrzut. Ustaw domyślnie.
  • Obiekty przydzielone przed zrzutem 1: obiekty, które zostały utworzone i pozostały w pamięci przed wykonaniem pierwszego zrzutu.
  • Obiekty alokowane między migawkami 1 i 2: wyświetl różnicę w liczbie obiektów między najnowszym a poprzednim migawką. Każdy nowy zrzut ekranu powoduje dodanie kolejnej wartości tego filtra do listy rozwijanej.
  • Zduplikowane ciągi: wartości ciągu, które zostały zapisane w pamięci wielokrotnie.
  • Obiekty zachowane przez odłączone węzły: obiekty, które są utrzymywane, ponieważ odłączony węzeł DOM się do nich odwołuje.
  • Obiekty zachowane przez konsolę Narzędzi deweloperskich: obiekty przechowywane w pamięci, ponieważ zostały ocenione lub z nimi przeprowadzono interakcję za pomocą konsoli Narzędzi deweloperskich.

Specjalne wpisy w sekcji Podsumowanie

Oprócz grupowania według konstruktorów widok Podsumowanie grupuje obiekty również według:

  • Wbudowane funkcje, takie jak Array lub Object.
  • Elementy HTML pogrupowane według tagów, np. <div>, <a>, <img> i inne.
  • Funkcje zdefiniowane w kodzie.
  • Kategorie specjalne, które nie są oparte na konstruktorach.

Wpisy konstruktora.

(array)

Ta kategoria obejmuje różne wewnętrzne obiekty podobne do tablic, które nie odpowiadają bezpośrednio obiektom widocznym w JavaScript.

Na przykład zawartość obiektów JavaScript Array jest przechowywana w dodatkowym obiekcie wewnętrznym o nazwie (object elements)[], aby ułatwić zmianę rozmiaru. Podobnie nazwane właściwości w obiektach JavaScriptu są często przechowywane w dodatkowych wewnętrznych obiektach o nazwie (object properties)[], które są też wymienione w kategorii (array).

(compiled code)

Ta kategoria obejmuje dane wewnętrzne, których V8 potrzebuje do uruchamiania funkcji zdefiniowanych przez JavaScript lub WebAssembly. Każdą funkcję można przedstawić na różne sposoby: od małej i wolnej do dużej i szybkiej.

V8 automatycznie zarządza wykorzystaniem pamięci w tej kategorii. Jeśli funkcja jest wykonywana wiele razy, V8 przeznacza na nią więcej pamięci, aby mogła działać szybciej. Jeśli funkcja nie była wykonywana przez jakiś czas, V8 może usunąć jej dane wewnętrzne.

(concatenated string)

Gdy V8 konkatenuje 2 ciągi znaków, np. za pomocą operatora JavaScript +, może przedstawić wynik wewnętrznie jako „konkatenowany ciąg znaków”, czyli strukturę danych Rope.

Zamiast kopiować wszystkie znaki z dwóch ciągów źródłowych do nowego ciągu, V8 przypisuje niewielki obiekt z wewnętrznymi polami o nazwach first i second, które wskazują te 2 ciągi źródłowe. Dzięki temu V8 oszczędza czas i pamięć. Z perspektywy kodu JavaScript są to zwykłe ciągi znaków, które zachowują się jak każdy inny ciąg znaków.

InternalNode

Ta kategoria reprezentuje obiekty przydzielone poza V8, takie jak obiekty C++ zdefiniowane przez Blink.

Aby wyświetlić nazwy klas C++, użyj Chrome for Testing i wykonaj te czynności:

  1. Otwórz Narzędzia deweloperskie i włącz Ustawienia > Eksperymenty > Pokaż opcję wyświetlania zasobów wewnętrznych w zrzutach stosu.
  2. Otwórz panel Pamięć, wybierz Zrzut Heap i włącz Udostępnij dane wewnętrzne (w tym dodatkowe szczegóły charakterystyczne dla implementacji).
  3. Odtwórz problem, który spowodował, że InternalNode zatrzymało dużo pamięci.
  4. Zrób zrzut stosu. Na tym zrzucie obiekty mają nazwy klas C++, a nie InternalNode.
(object shape)

Jak opisano w artykule Fast Properties in V8 (w języku angielskim), V8 śledzi ukryte klasy (lub kształty), aby można było efektywnie reprezentować wiele obiektów o tych samych właściwościach w tym samym porządku. Ta kategoria zawiera ukryte zajęcia o nazwie system / Map (niezwiązane z JavaScriptem Map) oraz powiązane z nimi dane.

(sliced string)

Gdy V8 musi przejąć podłańcuch, np. gdy kod JavaScript wywołuje String.prototype.substring(), V8 może zdecydować się na przydzielenie obiektu wyciętego ciągu, zamiast kopiować wszystkie istotne znaki z oryginalnego ciągu. Ten nowy obiekt zawiera wskaźnik do oryginalnego ciągu znaków i opisuje, który zakres znaków z pierwotnego ciągu ma być użyty.

Z punktu widzenia kodu JavaScript są to zwykłe ciągi znaków, które działają jak każdy inny ciąg. Jeśli pokrojowy ciąg znaków zajmuje dużo pamięci, program może wywołać problem 2869 i można podjąć celowe działania, aby „spłaszczyć” pokrojowy ciąg znaków.

system / Context

Obiekty wewnętrzne typu system / Context zawierają zmienne lokalne z closure, czyli zakresu JavaScriptu, do którego może mieć dostęp funkcja zagnieżdżona.

Każda instancja funkcji zawiera wewnętrzny wskaźnik do Context, w którym jest wykonywana, dzięki czemu może uzyskiwać dostęp do tych zmiennych. Chociaż obiekty Context nie są widoczne bezpośrednio w JavaScript, masz nad nimi bezpośrednią kontrolę.

(system)

Ta kategoria zawiera różne obiekty wewnętrzne, które nie zostały (jeszcze) sklasyfikowane w żaden bardziej znaczący sposób.

Porównanie

Widok Porównanie umożliwia znajdowanie obiektów, które wyciekły, przez porównywanie ze sobą kilku zrzutów. Na przykład wykonanie czynności i jej cofnięcie, np. otwarcie dokumentu i jego zamknięcie, nie powinno pozostawiać dodatkowych obiektów.

Aby sprawdzić, czy dana operacja nie powoduje wycieków:

  1. Przed wykonaniem operacji zrób zrzut stosu.
  2. Wykonywanie operacji. Oznacza to, że musisz wejść w interakcję ze stroną w sposób, który Twoim zdaniem może spowodować wyciek.
  3. Wykonaj odwrotną operację. Oznacza to, że należy wykonać odwrotną interakcję i powtórzyć ją kilka razy.
  4. Zrób drugi zrzut pamięci podręcznej i zmień jego widok na Porównanie, aby porównać go z zrzutem 1.

Widok Porównanie pokazuje różnicę między dwoma zrzutami. Po rozwinięciu rekordu sumy wyświetlane są dodane i usunięte wystąpienia obiektu:

Porównanie z wersją 1.

Widok Zawieranie

Widok Zawiera to „widok z lotu ptaka” struktury obiektów aplikacji. Umożliwia ona zaglądanie do funkcji zamykających, obserwowanie wewnętrznych obiektów maszyny wirtualnej, które razem tworzą obiekty JavaScript, oraz określanie, ile pamięci zużywa aplikacja na bardzo niskim poziomie.

Widok zawiera kilka punktów wejścia:

  • obiekty DOMWindow, Obiekty globalne dla kodu JavaScript.
  • GC roots. korzenie GC używane przez zbieracz śmieci maszyny wirtualnej. Korzenie GC mogą składać się z wbudowanych map obiektów, tabel symboli, stosów wątków maszyny wirtualnej, pamięci podręcznej kompilacji, zakresów uchwytów i uchwytów globalnych.
  • obiekty natywne, Obiekty przeglądarki „przesyłane” do maszyny wirtualnej JavaScriptu, aby umożliwić automatyzację, np. węzły DOM i reguły CSS.

Widok Containment.

Sekcja Aparaty retencyjne

Sekcja Zatrzymacze u dołu panelu Pamięć zawiera obiekty, które wskazują obiekt wybrany w widoku. Gdy wybierzesz inne obiekty w dowolnym widoku (z wyjątkiem widoku Statystyki), panel Pamięć zaktualizuje sekcję Utrzymujący.

Sekcja Elementy zachowujące.

W tym przykładzie wybrany ciąg znaków jest przechowywany przez właściwość x instancji Item.

Ignoruj elementy zachowujące

Możesz ukryć elementy stałe, aby sprawdzić, czy inne obiekty nie zastępują wybranego. Dzięki tej opcji nie musisz najpierw usuwać jej z kodu, a potem jeszcze raz robić zrzutu stosu.

Opcja „Ignoruj tę rezerwację” w menu.

Aby ukryć załącznik, kliknij prawym przyciskiem myszy i wybierz Ignoruj ten załącznik. Zignorowane osoby zachowujące są oznaczone jako ignored w kolumnie Odległość. Aby przestać ignorować wszystkie rezerwacje, na górze na pasku działań kliknij Przywróć zignorowane rezerwacje.

Znajdowanie konkretnego obiektu

Aby znaleźć obiekt w zbiorzonej stercie, możesz użyć skrótu Ctrl + F i wpisać identyfikator obiektu.

Nazwij funkcje, aby odróżnić zamknięcia

Warto nazwać funkcje, aby rozróżnić zamknięcia na zrzucie ekranu.

Na przykład w tym kodzie nie używa się funkcji nazwanych:

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

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

  return lC;
}

Ten przykład:

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

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

  return lC;
}

Funkcja nazwana w zamknięciu.

Odkrywanie wycieków danych do DOM

Profilator sterty może odzwierciedlać dwukierunkowe zależności między obiektami natywnymi przeglądarki (węzłami DOM i regułami CSS) a obiektami JavaScript. Pomaga to wykryć niewidoczne wyciek danych wynikające z unoszących się wokół zapomnianych, odłączonych poddrzew DOM.

Wycieki DOM mogą być większe, niż Ci się wydaje. Rozważ ten przykład. Kiedy odbierane są odpady #tree?

  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 przechowuje odwołanie do swojego rodzica (parentNode) i rekurencyjnie do #tree, więc dopiero gdy leafRef zostanie unieważniony, cały drzewo pod #tree staje się kandydatem do GC.

Poddrzewa DOM