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.

Profilator sterty pokazuje rozkład pamięci między obiekty JavaScript Twojej strony i powiązane węzły DOM. Za pomocą tej funkcji możesz robić zrzuty pamięci sterty w JS, analizować wykresy pamięci, porównywać zrzuty i wykrywać 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 przeanalizować, 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ęć wczyta i przeanalizuje obraz sterty, wyświetli łączny rozmiar dostępnych obiektów JavaScript pod tytułem obrazu w sekcji OBRAZY STERTY.

Łą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 z rozproszonymi obiektami 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. Za jego pomocą możesz wyszukiwać obiekty i ich wykorzystanie pamięci na podstawie 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. Możesz go używać do analizowania zamknięć i szczegółowego badania obiektów.
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 podsumowania 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 filtrze Klasa 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 korzenia, korzystając z najkrótszej prostej ścieżki przez węzły.
  • Shallow size (płytki rozmiar) to suma płytkich rozmiarów wszystkich obiektów utworzonych przez dany konstruktor. Rozmiar płytki to rozmiar pamięci przechowywanej przez sam obiekt. Zwykle tablice i ciągi mają większy rozmiar płytki. Zobacz też Rozmiary obiektów.
  • Zachowany rozmiar to maksymalny rozmiar zachowany w tym samym zbiorze 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 nieefektywnego wykorzystania pamięci.

Aby użyć tych filtrów, w najbardziej wysuniętym w prawo menu 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ę między obiektami w najnowszym i poprzednim migawce. 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ę w 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.
  • Specjalne kategorie, które nie są oparte na konstruktorach.

Wpisy w konstruktorze.

(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 wiele sposobów, od małych i wolnych do dużych i szybkich.

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 koniunguje 2 ciągi znaków, np. za pomocą operatora JavaScript +, może wewnętrznie przedstawić wynik jako „koniungowany ciąg znaków”, czyli strukturę danych Rope.

Zamiast kopiować wszystkie znaki z 2 ciągów znaków źródłowych do nowego ciągu, V8 przydziela mały obiekt z polami wewnętrznymi o nazwach firstsecond, które wskazują na 2 ciągi znaków źródłowych. Dzięki temu V8 oszczędza czas i pamięć. Z punktu widzenia 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 obejmuje 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ę, aby wyświetlić informacje wewnętrzne w migawkach 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. Wykonaj zrzut sterty. 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 przedstawiać wiele obiektów o tych samych właściwościach w tym samym porządku. Ta kategoria zawiera ukryte klasy o nazwie system / Map (niezwiązane z JavaScriptem Map) i powiązane z nimi dane.

(sliced string)

Gdy V8 musi pobrać podciąg, np. gdy kod JavaScript wywołuje funkcję String.prototype.substring(), V8 może przydzielić obiekt podcięty ciąg znaków zamiast kopiować wszystkie odpowiednie znaki z pierwotnego ciągu znaków. 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 zachowują się jak każdy inny ciąg znaków. 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 pozwala znaleźć wycieki danych, porównując ze sobą różne migawki. 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 wykonaj zrzut sterty.
  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 ekranu stosu i zmień jego widok na Porównanie, aby porównać go z zrzutem ekranu 1.

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

Porównanie z wersją 1.

Widok Zawieranie

Widok Zawartość 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ę Zatrzymanie.

Sekcja Aparaty retencyjne.

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

Ignorowanie elementów zachowujących

Możesz ukryć elementy stałe, aby sprawdzić, czy inne obiekty nie zastępują wybranego. Dzięki tej opcji nie musisz najpierw usuwać tego elementu z kodu, a potem ponownie robić zrzut pamięci.

Opcja „Ignoruj tę rezerwację” w menu.

Aby ukryć załącznik, kliknij prawym przyciskiem myszy i wybierz Ignoruj ten załącznik. Ignorowane pozycje stałe są oznaczone jako ignored w kolumnie Odległość. Aby przestać ignorować wszystkie rezerwacje, na górze na pasku czynności 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.

Nazywanie funkcji w celu odróżnienia ich od funkcji zamykających

Nazwa funkcji bardzo pomaga w odróżnianiu zamknięć na zrzucie.

Na przykład w tym kodzie nie używamy 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 wykrywać niewidoczne wycieki danych spowodowane zapomnianymi, oderwanymi poddrzewami DOM.

Wycieki danych do 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 rekursywnie do #tree, więc dopiero gdy leafRef zostanie unieważniony, cały drzewo pod #tree będzie kandydatem na GC.

Poddrzewa DOM