Rejestruj zrzuty sterty

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

Dowiedz się, jak nagrywać zrzuty sterty w sekcji Pamięć > Profile > Zrzut sterty i znajdować wycieki pamięci.

Program profilujący sterty pokazuje rozkład pamięci według obiektów JavaScript strony i powiązanych węzłów DOM. Służy do wykonywania zrzutów sterty JS, analizowania wykresów pamięci, porównywania zrzutów i wykrywania wycieków pamięci. Więcej informacji znajdziesz w artykule Drzewo przechowywania obiektów.

Zrób zrzut

Aby zrobić zrzut sterty:

  1. Na stronie, którą chcesz profilować, otwórz Narzędzia dla programistów i przejdź do panelu Pamięć.
  2. Wybierz typ profilowania radio_button_checked Zrzut sterty, a następnie wybierz instancję maszyny wirtualnej JavaScript i kliknij Zrób zrzut.

Wybrany typ profilowania i instancja maszyny wirtualnej JavaScript.

Gdy panel Pamięć wczytuje i analizuje zrzut, pod tytułem zrzutu w sekcji HEAP wyświetla łączny rozmiar dostępnych obiektów JavaScript.

Łączny rozmiar osiągalnych obiektów.

Zrzuty pokazują tylko te obiekty z wykresu pamięci, które są dostępne z obiektu globalnego. Wykonywanie zrzutu zawsze zaczyna się od czyszczenia pamięci.

Migawka sterty rozrzuconych obiektów Item.

Wyczyść zrzuty

Aby usunąć wszystkie zrzuty, kliknij zablokuj Wyczyść wszystkie profile:

Wyczyść wszystkie profile.

Wyświetl zrzuty

Aby sprawdzać zrzuty z różnych perspektyw w różnych celach, wybierz jeden z widoków z menu u góry:

Wyświetl treści Purpose
Podsumowanie Obiekty pogrupowane według nazw konstruktorów. Pozwala wyszukiwać obiekty i wykorzystywać pamięć w zależności od typu. Przydatny przy śledzeniu wycieków DOM.
Porównanie Różnice między 2 zrzutami dysku. Służy do porównania co najmniej 2 zrzutów – przed operacją i po niej. Potwierdź obecność i przyczynę wycieku pamięci, sprawdzając delta zwolnionej pamięci i liczby odwołań.
Izolacja Zawartość sterty Daje lepszy wgląd w strukturę obiektów i pomaga analizować obiekty, do których odwołuje się globalna przestrzeń nazw (okno) w celu znalezienia tego, co je trzyma. Służy do analizowania zamknięcia i szczegółowości obiektów.
Statystyki Wykres kołowy alokacji pamięci Zobacz rzeczywiste rozmiary części pamięci przydzielonych do kodu, ciągów tekstowych, tablic JS, tablic o typach i obiektach systemowych.

Widok podsumowania wybrany z menu u góry.

Widok podsumowania

Początkowo w widoku Podsumowanie w kolumnie Konstruktorzy otwiera się zrzut stosu. Możesz rozwinąć konstruktory, aby zobaczyć obiekty, które utworzyły.

Widok podsumowania z rozwiniętym konstruktorem.

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

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

  • Odległość wskazuje odległość do pierwiastka przy użyciu najkrótszej prostej ścieżki węzłów.
  • Płytki rozmiar przedstawia sumę płytkich rozmiarów wszystkich obiektów utworzonych przez określony konstruktor. „Mały rozmiar” to rozmiar pamięci przechowywanej przez sam obiekt. Ogólnie tablice i ciągi znaków mają większe płytki rozmiar. Zobacz też Rozmiary obiektów.
  • Zachowany rozmiar pokazuje maksymalny rozmiar przechowywanych obiektów w tym samym zestawie. Zachowany rozmiar pamięci to rozmiar pamięci, który można zwolnić przez usunięcie obiektu i uniemożliwienie osiągnięcia jego wartości zależnych. Zobacz też Rozmiary obiektów.

Po rozwinięciu konstruktora w widoku Podsumowanie widoczne są wszystkie jego instancje. Każda instancja otrzymuje w odpowiednich kolumnach podział na rozmiary płytki i zachowany. Liczba po znaku @ to unikalny identyfikator obiektu. Umożliwia porównywanie zrzutów sterty dla poszczególnych obiektów.

Wpisy specjalne w podsumowaniu

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

  • funkcji wbudowanych, takich jak Array lub Object;
  • Funkcje zdefiniowane w kodzie.
  • Kategorie specjalne, które nie są oparte na konstruktorach.

Wpisy konstruktora.

(array)

Ta kategoria zawiera różne wewnętrzne obiekty przypominające tablice, które nie odpowiadają bezpośrednio obiektom widocznym w skrypcie JavaScript.

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

(compiled code)

Ta kategoria zawiera dane wewnętrzne, których V8 potrzebuje do uruchamiania funkcji zdefiniowanych przez JavaScript lub WebAssembly. Każda funkcja może być przedstawiona na różne sposoby: od małych i wolnych po duże i szybkie.

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

(concatenated string)

Gdy V8 łączy 2 ciągi, np. z operatorem JavaScript +, może przedstawić wynik wewnętrznie w postaci „połączonego ciągu znaków” nazywanego też strukturą danych Lopa.

Zamiast kopiować wszystkie znaki z 2 ciągów źródłowych do nowego ciągu znaków, w V8 przydzielany jest mały obiekt z polami wewnętrznymi o nazwie 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 po prostu zwykłe ciągi znaków i działają tak samo jak inne.

InternalNode

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

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

  1. Otwórz Narzędzia deweloperskie i włącz ustawienia Ustawienia > Eksperymenty > pole wyboru Pokaż opcję udostępniania zasobów wewnętrznych w zrzutach stosu.
  2. Otwórz panel Pamięć, wybierz radio_button_checked Zrzut stosu i włącz radio_button_checked Udostępnij dane wewnętrzne (zawiera dodatkowe szczegóły związane z implementacją).
  3. Odtwórz problem, który spowodował, że InternalNode zachował dużą ilość pamięci.
  4. Zrób zrzut sterty. W tym zrzucie obiekty mają nazwy klas C++ zamiast InternalNode.
(object shape)

Jak opisano w sekcji Szybkie właściwości w wersji 8, wersja 8 śledzi ukryte klasy (czyli kształty), aby można było skutecznie przedstawić wiele obiektów o tych samych właściwościach w tej samej kolejności. Ta kategoria zawiera ukryte klasy o nazwie system / Map (niezwiązane z językiem JavaScript Map) i powiązane z nimi dane.

(sliced string)

Gdy V8 musi wybrać podłańcuch, np. gdy kod JavaScript wywołuje String.prototype.substring(), V8 może przydzielić obiekt wycięty ciąg znaków, zamiast kopiować wszystkie odpowiednie znaki z pierwotnego ciągu. Ten nowy obiekt zawiera wskaźnik do pierwotnego ciągu i opisuje zakres znaków z pierwotnego ciągu, który ma zostać użyty.

Z perspektywy kodu JavaScript są to po prostu zwykłe ciągi znaków i działają tak samo jak inne. Jeśli wycinek ciągu znaków przechowuje dużą ilość pamięci, program mógł wywołać problem 2869 i korzystnie wpływać na wykonanie celowych czynności w celu „spłaszczenia” wyciętego ciągu znaków.

system / Context

Obiekty wewnętrzne typu system / Context zawierają zmienne lokalne z zamknięcia – zakresu JavaScript, do którego ma dostęp funkcja zagnieżdżona.

Każde wystąpienie funkcji zawiera wewnętrzny wskaźnik do funkcji Context, która uruchamia ją, aby mieć dostęp do tych zmiennych. Chociaż obiekty Context nie są bezpośrednio widoczne w kodzie JavaScript, masz nad nimi bezpośrednią kontrolę.

(system)

Ta kategoria zawiera różne obiekty wewnętrzne, które nie zostały (jeszcze) sklasyfikowane w bardziej zrozumiały 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 wykonywanie czynności i cofanie jej, takie jak otwarcie dokumentu i zamknięcie go, nie powinno pozostawiać po sobie żadnych dodatkowych obiektów.

Aby sprawdzić, czy dana operacja nie powoduje wycieku:

  1. Przed wykonaniem operacji wykonaj zrzut sterty.
  2. Wykonaj operację. Oznacza to, że wchodź w interakcje ze stroną w sposób, który Twoim zdaniem może powodować wyciek danych.
  3. Wykonaj operację odwrotną. Oznacza to, że należy wykonać odwrotną czynność i powtórzyć ją kilka razy.
  4. Zrób drugi zrzut stosu i zmień jego widok na Porównanie i porównaj go z zrzutem ekranu 1.

Widok Porównanie pokazuje różnicę między 2 migawkami. Po rozwinięciu wpisu wyświetlają się dodane i usunięte instancje obiektów:

Porównanie z Przeglądem dnia 1.

Widok zamknięć

Widok Kontener to ogólny widok struktury obiektów aplikacji. Pozwala zajrzeć do wnętrza zamknięcia funkcji, obserwować wewnętrzne obiekty maszyn wirtualnych, które składają się na obiekty JavaScript, i sprawdzać, ile pamięci używa aplikacja na bardzo niskim poziomie.

Widok ten udostępnia kilka punktów wejścia:

  • obiektów DOMWindow, Globalne obiekty kodu JavaScript.
  • Główne katalogi GC. Katalogi główne GC używane przez kolektor czyszczenia maszyny wirtualnej. Katalogi główne GC mogą się składać z wbudowanych map obiektów, tabel symboli, stosów wątków maszyn wirtualnych, pamięci podręcznych kompilacji, zakresów uchwytów i uchwytów globalnych.
  • Obiekty natywne. „przekazane” obiekty przeglądarki wewnątrz maszyny wirtualnej JavaScriptu, co umożliwia automatyzację, np. w przypadku węzłów DOM i reguł CSS.

widok Kontener.

Sekcja Użytkownicy z zachowaniem

Sekcja Przechowywacze u dołu panelu Pamięć zawiera obiekty wskazujące obiekt zaznaczony w widoku.

Sekcja Zatrzymujący.

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

Znajdź konkretny obiekt

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

Nazwij funkcje pozwalające odróżnić zamknięcia

Nazywanie funkcji jest bardzo pomocne, ponieważ można je łatwo rozróżnić w zrzucie dysku.

Na przykład ten kod nie zawiera funkcji nazwanych:

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

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

  return lC;
}

W tym przykładzie:

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.

Wykrywanie wycieków DOM

Program profilujący sterty może odzwierciedlać dwukierunkowe zależności między natywnymi obiektami przeglądarki (węzłami DOM i regułami CSS) a obiektami JavaScript. Pomaga to w wykrywaniu niewidocznych wycieków spowodowanych zapomnianym odłączonymi poddrzewami DOM.

Wycieki DOM mogą być większe, niż myślisz. Przeanalizuj ten przykład. Kiedy są zbierane śmieci z usługi #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 zachowuje odniesienie do swojego elementu nadrzędnego (parentNode) i rekurencyjnie do #tree. Dlatego tylko gdy argument leafRef zostanie unieważniony, to całe drzewo pod #tree jest kandydatem do GC.

Poddrzewa DOM