Rozwiązywanie problemów z pamięcią

Dowiedz się, jak używać Chrome i Narzędzi deweloperskich, aby wykrywać problemy z pamięcią, które wpływają na wydajność stron, takie jak wycieki pamięci, nadmierne operacje w pamięci czy częste usuwanie czyszczenia pamięci.

Podsumowanie

  • Za pomocą Menedżera zadań Chrome możesz sprawdzić, ile pamięci obecnie wykorzystuje Twoja strona.
  • Wizualizacja wykorzystania pamięci w czasie za pomocą nagrań na osi czasu.
  • Identyfikowanie odłączonych drzew DOM (częsta przyczyna wycieków pamięci) przy użyciu zrzutów sterty.
  • Dowiedz się, kiedy nowa pamięć jest przydzielana na stercie JS za pomocą nagrań na osi czasu alokacji.

Przegląd

Zgodnie z duchem modelu wydajności RAIL działania związane z wydajnością powinny być skupione na użytkownikach.

Problemy z pamięcią są ważne, ponieważ często użytkownicy je dostrzegają. Użytkownicy mogą interpretować problemy z pamięcią na następujące sposoby:

  • Wydajność strony staje się z czasem coraz gorsza. Prawdopodobnie jest to objaw wycieku pamięci. Wyciek pamięci ma miejsce, gdy błąd na stronie sprawia, że z czasem strona coraz bardziej zużywa pamięć.
  • Wydajność strony jest stale niska. Prawdopodobnie jest to objaw zaburzeń pamięci. Zbyt duża ilość pamięci występuje, gdy strona wykorzystuje więcej pamięci niż jest to konieczne do uzyskania optymalnej szybkości.
  • Wydajność strony jest opóźniona lub prawdopodobnie zatrzymuje się często. Prawdopodobnie jest to objaw częstego odśmiecania pamięci. Czyszczenie pamięci ma miejsce, gdy przeglądarka odzyskuje pamięć. To przeglądarka zadecyduje, kiedy to nastąpi. Podczas zbierania danych wykonywanie skryptu jest wstrzymane. Jeśli więc przeglądarka często pobiera odpady, wykonywanie skryptów jest często wstrzymywane.

Za dużo pamięci: ile to „za dużo”?

Wyciek pamięci można łatwo zdefiniować. Jeśli witryna zużywa coraz więcej pamięci, oznacza to, że doszło do wycieku. Ale za dużo pamięci jest trochę trudniejsze do przypięcia. Co kwalifikuje się jako „nadmierne wykorzystanie pamięci”?

Nie ma tu sztywnych wartości, ponieważ różne urządzenia i przeglądarki mają różne możliwości. Strona, która działa płynnie na wysokiej klasy smartfonie, może ulec awarii na słabszych smartfonach.

Najważniejsze jest użycie modelu RAIL i skupienie się na użytkownikach. Dowiedz się, jakie urządzenia są popularne u Twoich użytkowników, i przetestuj na nich swoją stronę. Jeśli działanie jest stale nieprawidłowe, być może strona przekracza możliwości pamięci tych urządzeń.

Monitoruj użycie pamięci w czasie rzeczywistym za pomocą Menedżera zadań Chrome

Jako punkt wyjścia do analizy problemów z pamięcią użyj Menedżera zadań Chrome. Menedżer zadań to monitor w czasie rzeczywistym, który informuje, ile pamięci obecnie wykorzystuje strona.

  1. Naciśnij Shift+Esc lub przejdź do menu głównego Chrome i wybierz Więcej narzędzi > Menedżer zadań, aby otworzyć Menedżera zadań.

    Otwieranie Menedżera zadań

  2. Kliknij prawym przyciskiem myszy nagłówek tabeli w Menedżerze zadań i włącz pamięć JavaScript.

    Włączanie pamięci JS

Te dwie kolumny różnią się informacjami o tym, jak strona wykorzystuje pamięć:

  • Kolumna Pamięć reprezentuje pamięć natywną. Węzły DOM są przechowywane w pamięci natywnej. Jeśli ta wartość rośnie, tworzone są węzły DOM.
  • Kolumna Pamięć JavaScript przedstawia stertę JS. Ta kolumna zawiera 2 wartości. Interesująca Cię wartość to bieżąca liczba (liczba w nawiasach). Aktywna liczba reprezentuje ilość pamięci używanej przez osiągalne obiekty na stronie. Jeśli liczba będzie rosnąć, oznacza to, że są tworzone nowe obiekty lub powiększają się istniejące obiekty.

Wizualizacja wycieków pamięci za pomocą nagrań wydajności

Jako punktu wyjścia do analizy możesz też użyć panelu Skuteczność. Panel wydajności umożliwia wizualizację wykorzystania pamięci przez stronę w czasie.

  1. Otwórz panel Skuteczność w Narzędziach deweloperskich.
  2. Zaznacz pole wyboru Pamięć.
  3. Nagraj

Aby zademonstrować rejestrowanie wydajności, użyj tego kodu:

var x = [];

function grow() {
  for (var i = 0; i < 10000; i++) {
    document.body.appendChild(document.createElement('div'));
  }
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

Po każdym naciśnięciu przycisku, do którego odwołuje się kod, do treści dokumentu dołączane jest dziesięć tysięcy węzłów div, a ciąg miliona znaków x jest przekazywany do tablicy x. Uruchomienie tego kodu spowoduje utworzenie na osi czasu zapisu takiego jak ten zrzut ekranu:

prosty przykład wzrostu

Pierwsza z nich to omówienie interfejsu użytkownika. Wykres HEAP w panelu Przegląd (poniżej NET) przedstawia stertę JS. Pod panelem Przegląd znajduje się panel Licznik. Wykorzystanie pamięci jest podzielone według sterty JS (tak samo jak na wykresie HEAP w panelu Przegląd), dokumenty, węzły DOM, detektory i pamięć GPU. Wyłączenie pola wyboru spowoduje ukrycie go na wykresie.

Analiza kodu w porównaniu ze zrzutem ekranu. Jeśli spojrzysz na licznik węzłów (zielony wykres), przekonasz się, że pasuje on do kodu. Liczba węzłów zwiększa się w określonych krokach. Możesz przyjąć, że każde zwiększenie liczby węzłów jest wywołaniem funkcji grow(). Wykres stosu JS (niebieski) nie jest tak prosty. Zgodnie ze sprawdzonymi metodami pierwszy spadek jest w rzeczywistości wymuszonym usuwaniem odpadów (co osiąga się po naciśnięciu przycisku Zbieraj śmieci). W miarę postępów nagrywania możesz zauważyć, że rozmiar sterty JS rośnie. To naturalne i oczekiwane: kod JavaScript tworzy węzły DOM po każdym kliknięciu przycisku i wykonuje mnóstwo pracy, gdy tworzy ciąg miliona znaków. Kluczowe jest tutaj to, że sterta JS kończy się wyżej niż się zaczyna (w tym przypadku „początek” jest punktem po wymuszeniu czyszczenia pamięci). W rzeczywistości, jeśli zauważysz ten wzorzec zwiększania rozmiaru sterty JS lub rozmiaru węzła, może to oznaczać wyciek pamięci.

Wykrywanie wycieków pamięci odłączonego drzewa DOM za pomocą zrzutów sterty

Węzeł DOM może zostać usunięty tylko wtedy, gdy nie ma do niego żadnych odwołań z drzewa DOM strony ani z kodu JavaScript. Węzeł jest uważany za „odłączony”, gdy jest usunięty z drzewa DOM, ale niektóre skrypty JavaScript nadal się do niego odwołują. Odłączone węzły DOM są częstą przyczyną wycieków pamięci. W tej sekcji dowiesz się, jak używać profili profili sterty dostępnych w Narzędziach deweloperskich do identyfikowania odłączonych węzłów.

Oto prosty przykład odłączonych węzłów DOM.

var detachedTree;

function create() {
  var ul = document.createElement('ul');
  for (var i = 0; i < 10; i++) {
    var li = document.createElement('li');
    ul.appendChild(li);
  }
  detachedTree = ul;
}

document.getElementById('create').addEventListener('click', create);

Kliknięcie przycisku, do którego odwołuje się kod, tworzy węzeł ul z 10 elementami podrzędnymi li. Kody te odwołują się do tych węzłów, ale nie istnieją w drzewie DOM, więc zostały odłączone.

Zrzuty sterty to jeden ze sposobów identyfikacji odłączonych węzłów. Jak sama nazwa wskazuje, zrzuty stosu pokazują rozkład pamięci między obiekty JS i węzły DOM strony w momencie wykonywania zrzutu.

Aby utworzyć zrzut, otwórz Narzędzia deweloperskie, przejdź do panelu Pamięć, wybierz opcję Zrzut stosu, a następnie kliknij Zrób zrzut ekranu.

zrób zrzut stosu

Przetworzenie i wczytanie zrzutu może trochę potrwać. Po zakończeniu wybierz go w panelu po lewej stronie (o nazwie SNAPSHOTS).

Aby wyszukać odłączone drzewa DOM, w polu tekstowym Filtr klasy wpisz Detached.

filtrowanie odłączonych węzłów

Aby zbadać oddalone drzewo, możesz powiększyć karaty.

sprawdzanie odłączonego drzewa

Węzły zaznaczone na żółto mają bezpośrednie odwołania z kodu JavaScript. Węzły zaznaczone na czerwono nie mają bezpośrednich odwołań. Żyją tylko dlatego, że wchodzą w skład żółtego drzewa węzła. Skupiamy się zwykle na żółtych węzłach. Napraw kod, by żółty węzeł nie działał dłużej, niż powinien. Pozbądź się też czerwonych węzłów, które wchodzą w skład żółtego drzewa.

Aby dokładniej zbadać ten problem, kliknij żółty węzeł. W panelu Obiekty znajdziesz więcej informacji o kodzie, który się do niego odwołuje. Na przykład na zrzucie ekranu poniżej możesz zobaczyć, że zmienna detachedTree odwołuje się do węzła. Aby rozwiązać ten konkretny wyciek pamięci, należy zbadać kod, który używa dyrektywy detachedTree, i upewnić się, że usuwa on swoje odwołanie do węzła, gdy nie jest już potrzebne.

badanie żółtego węzła

Identyfikuj wycieki pamięci sterty JS za pomocą osi czasu alokacji

Oś czasu alokacji to kolejne narzędzie, które pomaga wykrywać wycieki pamięci w stercie JS.

Aby zademonstrować oś czasu alokacji, użyj tego kodu:

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

Za każdym razem, gdy przycisk, do którego odwołuje się kod, jest wypchnięty, do tablicy x dodawany jest ciąg miliona znaków.

Aby zarejestrować oś czasu alokacji, otwórz Narzędzia deweloperskie, przejdź do panelu Profile, wybierz opcję Zarejestruj oś czasu przydziału, naciśnij przycisk Rozpocznij, wykonaj działanie, które prawdopodobnie powoduje wyciek pamięci, a gdy skończysz, naciśnij przycisk Zatrzymaj nagrywanie (przycisk Zatrzymaj nagrywanie).

Podczas nagrywania sprawdź, czy na osi czasu alokacji pojawią się niebieskie paski, tak jak na zrzucie ekranu poniżej.

nowe przydziały

Te niebieskie paski oznaczają nowe przydziały pamięci. Te nowe przydziały pamięci to kandydaci do wycieków pamięci. Możesz powiększyć pasek, aby przefiltrować panel Konstruktora i wyświetlić tylko obiekty, które zostały przydzielone w określonym przedziale czasu.

powiększony harmonogram alokacji

Rozwiń obiekt i kliknij jego wartość, aby wyświetlić więcej informacji na jego temat w panelu Obiekt. Na przykład na zrzucie ekranu poniżej widać szczegóły obiektu, który został niedawno przydzielony, i widać, że został on przydzielony do zmiennej x w zakresie Window.

szczegóły obiektu

Badanie przydziału pamięci według funkcji

Aby wyświetlić przydział pamięci według funkcji JavaScriptu, użyj typu Próbkowanie przydziałów w panelu Pamięć.

Program profilujący alokacji rekordów

  1. Wybierz opcję Próbkowanie przydziału. Jeśli na stronie znajduje się instancja robocza, możesz ją wybrać jako miejsce docelowe profilowania w menu obok przycisku Rozpocznij.
  2. Naciśnij przycisk Start.
  3. Wykonaj czynności na stronie, którą chcesz zbadać.
  4. Gdy skończysz, naciśnij przycisk Zatrzymaj.

W Narzędziach deweloperskich znajdziesz zestawienie przydziału pamięci według funkcji. Widok domyślny to Wysoki (od dołu). U góry widać funkcje, które przydzieliły najwięcej pamięci.

Profil przydziału

Wykrywaj częste usuwanie odpadów

Jeśli strona często się zatrzymuje, może to oznaczać, że występują problemy z odśmiecaniem.

Aby wykryć częste usuwanie czyszczenia pamięci, możesz skorzystać z Menedżera zadań Chrome lub nagrań z osi czasu na osi czasu. W Menedżerze zadań częste i rosnące wartości Pamięć lub Pamięć JavaScript oznaczają częste czyszczenie pamięci. W nagraniach osi czasu wykresy często rosnących i spadających sterty JS lub liczby węzłów wskazują na częste usuwanie odpadów.

Po zidentyfikowaniu problemu możesz użyć rejestracji na osi czasu alokacji, aby dowiedzieć się, gdzie przydzielana jest pamięć i które funkcje powodują przydziały.