Rozwiązywanie problemów z pamięcią

Kayce Basques
Kayce Basques

Dowiedz się, jak używać Chrome i Narzędzi deweloperskich do znajdowania problemów z pamięcią, które mają wpływ na wydajność stron, w tym wycieków pamięci, nadmiaru pamięci i częstych operacji czyszczenia pamięci.

Podsumowanie

  • Sprawdź, ile pamięci obecnie wykorzystuje Twoja strona dzięki Menedżerowi zadań Chrome.
  • Wizualizuj wykorzystanie pamięci w czasie za pomocą nagrań na osi czasu.
  • Zidentyfikuj odłączone drzewa DOM (częstą przyczynę wycieków pamięci) za pomocą zrzutów sterty.
  • Dzięki nagraniom na osi czasu alokacji możesz sprawdzać, kiedy na stercie JS jest przydzielana nowa pamięć.

Opis

Zgodnie z modelem skuteczności RAIL w działaniach ukierunkowanych na zwiększenie skuteczności należy skupić się na użytkownikach.

Problemy z pamięcią są ważne, ponieważ często są widoczne dla użytkowników. Użytkownicy mogą postrzegać problemy z pamięcią w ten sposób:

  • Wydajność strony stopniowo pogarsza się z czasem. To może być objaw wycieku pamięci. Wyciek pamięci występuje, gdy błąd na stronie powoduje, że z czasem strona stopniowo wykorzystuje coraz więcej pamięci.
  • Wydajność strony stale jest niska. To może być objaw wady pamięci. Zbyt duża ilość pamięci dotyczy sytuacji, w której strona wykorzystuje więcej pamięci, niż jest to konieczne do uzyskania optymalnej szybkości.
  • Wydajność strony jest opóźniona lub wydaje się, że często jest wstrzymywana Może to być objawem częstego usuwania śmieci. Wyczyszczenie pamięci ma miejsce, gdy przeglądarka odzyskuje pamięć. To przeglądarka decyduje, kiedy to nastąpi. Podczas kolekcji wykonywanie wszystkich skryptów jest wstrzymywane. Jeśli więc przeglądarka będzie często zbierać śmieci, wykonywanie skryptu będzie mocno wstrzymana.

Nadmierna ilość pamięci: ile to „za dużo”?

Wyciek pamięci łatwo określić. Jeśli strona stopniowo wykorzystuje coraz więcej pamięci, oznacza to, że doszło do wycieku. Zbyt duża ilość pamięci jest jednak trudniejsza do uchwycenia. Co kwalifikuje się jako „używanie zbyt dużej ilości pamięci”?

Nie ma tu sztywnych wartości, ponieważ różne urządzenia i przeglądarki mają różne możliwości. Ta sama strona, która działa płynnie na zaawansowanym smartfonie, może ulec awarii na smartfonie niskiej jakości.

Kluczem jest tu wykorzystanie modelu RAIL i skupienie się na użytkownikach. Sprawdź, jakie urządzenia są popularne wśród Twoich użytkowników, a potem przetestuj na nich swoją stronę. Jeśli strona nie przestanie działać prawidłowo, strona może wykorzystywać zbyt dużo pamięci tych urządzeń.

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

Jako punktu wyjścia do zbadania problemu z pamięcią używaj Menedżera zadań Chrome. Menedżer zadań to monitor w czasie rzeczywistym, który pokazuje, ile pamięci obecnie wykorzystuje strona.

  1. Aby otworzyć Menedżera zadań, naciśnij Shift+Esc lub otwórz menu główne Chrome i wybierz Więcej narzędzi > Menedżer 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 2 kolumny informują 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 reprezentuje stertę JS. Ta kolumna zawiera 2 wartości. Wartość, która Cię interesuje, to rzeczywista liczba (liczba w nawiasie). Liczba aktywnych elementów wskazuje, ile pamięci wykorzystują dostępne obiekty na stronie. Jeśli ta liczba rośnie, oznacza to, że tworzone są nowe obiekty lub liczba istniejących obiektów.

Wizualizuj wycieki pamięci za pomocą nagrań z występów

Panel skuteczności może też służyć jako punkt wyjścia do analizy zagrożeń. W panelu Wydajność możesz zobaczyć wykorzystanie pamięci przez stronę w czasie.

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

Aby zademonstrować nagrania w pamięci wyników, przeanalizuj ten kod:

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 w kodzie, do treści dokumentu dołączanych jest 10 tys. węzłów div, a do tablicy x jest przekazywany ciąg milionów znaków typu x. Po uruchomieniu tego kodu zostanie utworzone nagranie osi czasu, takie jak ten zrzut ekranu:

prosty przykład wzrostu

Najpierw wyjaśnij interfejs. Wykres HEAP w panelu Przegląd (poniżej NET) przedstawia stertę JS. Pod panelem Przegląd znajduje się panel Licznik. Tutaj możesz wyświetlić wykorzystanie pamięci z podziałem na stertę JS (tak samo jak na wykresie HEAP w panelu Przegląd), dokumenty, węzły DOM, detektory i pamięć GPU. Wyłączenie pola wyboru powoduje ukrycie go na wykresie.

Teraz przeanalizujemy kod i porównamy go ze zrzutem ekranu. Gdy spojrzysz na licznik węzłów (zielony wykres), możesz zobaczyć, że jest on zgodny z kodem. Liczba węzłów wzrasta w dyskretnych krokach. Możesz przyjąć, że każde zwiększenie liczby węzłów jest wywołaniem metody grow(). Wykres sterty JavaScriptu (niebieski wykres) nie jest tak prosty. Zgodnie ze sprawdzonymi metodami pierwszy krok to w rzeczywistości wymuszone wyrzucanie śmieci (można to osiągnąć przez naciśnięcie przycisku zbierania odpadów). W miarę postępów nagrywania widać, że rozmiar sterty JS gwałtownie rośnie. To naturalne i spodziewane: kod JavaScript tworzy węzły DOM przy każdym kliknięciu przycisku i wykona wiele pracy, gdy tworzy ciąg miliona znaków. Najważniejszą kwestią jest to, że sterta JS kończy się wyżej niż na początku (w tym miejscu „początek” to punkt po wymuszonym odczyszczeniu pamięci). W świecie rzeczywistym, jeśli zauważysz ten wzorzec zwiększania rozmiaru sterty JS lub węzła, potencjalnie może to oznaczać wyciek pamięci.

Wykrywaj wycieki pamięci odłączonego drzewa DOM za pomocą zrzutów sterty

Węzeł DOM może być zbierane tylko wtedy, gdy nie ma do niego odwołań z drzewa DOM strony ani z kodu JavaScript. Mówi się, że węzeł jest „odłączony”, gdy jest usuwany z drzewa DOM, ale niektóre skrypty JavaScript nadal się do niego odwołują. Odłączone węzły DOM to częsta przyczyna wycieku pamięci. Ta sekcja wyjaśnia, jak za pomocą 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, powoduje utworzenie węzła ul z 10 elementami podrzędnymi li. Do tych węzłów odwołuje się kod, ale nie ma ich w drzewie DOM, więc są odłączone.

Zrzuty sterty to jeden ze sposobów identyfikowania odłączonych węzłów. Zgodnie z nazwą zrzuty sterty pokazują rozkład pamięci między obiektami JS strony i węzłami DOM w momencie wykonania zrzutu.

Aby utworzyć zrzut, otwórz Narzędzia deweloperskie i przejdź do panelu Pamięć, wybierz opcję Zrzut sterty, a następnie naciśnij przycisk Zrób zrzut ekranu.

zrób zrzut sterty

Przetwarzanie i wczytanie zrzutu może trochę potrwać. Gdy skończysz, wybierz go na panelu po lewej stronie (o nazwie ZRZUTY SKRÓTY HEAP).

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

filtrowanie odłączonych węzłów

Rozbuduj karaty, aby zbadać odłączone drzewo.

analiza odłączonego drzewa

Węzły zaznaczone na żółto mają bezpośrednie odwołania do nich z kodu JavaScript. Węzły podświetlone na czerwono nie mają bezpośrednich odwołań. Żyją tylko dlatego, że należą do żółtego drzewa węzła. Chcesz skupić się na żółtych węzłach. Napraw kod tak, aby żółty węzeł nie był aktywny dłużej, niż jest to konieczne. Pozbądź się też czerwonych węzłów, które są częścią żółtego drzewa węzła.

Kliknij żółty węzeł, aby dokładniej go zbadać. W panelu Obiekty znajdziesz więcej informacji o kodzie, który się do niego odwołuje. Na przykład na zrzucie ekranu poniżej widać, że zmienna detachedTree odwołuje się do węzła. Aby rozwiązać ten problem, przeanalizuj kod, który korzysta z metody detachedTree, i upewnij się, że usuwa ono 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 pomoże Ci wykrywać wycieki pamięci na 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 jest naciskany przycisk, do którego odwołuje się kod, do tablicy x dodawany jest ciąg miliona znaków.

Aby nagrać oś czasu alokacji, otwórz Narzędzia deweloperskie, przejdź do panelu Profile, wybierz opcję Record Allocation Timeline (Zarejestruj oś czasu alokacji), naciśnij przycisk Start, wykonaj działanie, które prawdopodobnie powoduje wyciek pamięci, a następnie naciśnij przycisk Zatrzymaj nagrywanie (przycisk Zatrzymaj nagrywanie).

Podczas nagrywania zwróć uwagę, czy na osi czasu alokacji pojawiły się niebieskie paski, jak na poniższym zrzucie ekranu.

nowe przydziały

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

oś czasu powiększonego przydziału

Rozwiń obiekt i kliknij jego wartość, aby w panelu Obiekt wyświetlić więcej informacji na jego temat. Jeśli na przykład na zrzucie ekranu poniżej wyświetlisz szczegóły nowo przydzielonego obiektu, zobaczysz, że jest on przydzielony do zmiennej x w zakresie Window.

szczegóły obiektu

Zbadaj alokację pamięci według funkcji

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

Program profilujący alokacji rekordu

  1. Wybierz opcję Przydział próbkowania. Jeśli na stronie znajduje się instancja robocza, możesz ją wybrać jako cel profilowania za pomocą menu obok przycisku Rozpocznij.
  2. Naciśnij przycisk Start.
  3. Wykonaj działania na stronie, którą chcesz zbadać.
  4. Gdy skończysz, naciśnij przycisk Stop.

W Narzędziach deweloperskich znajdziesz podział alokacji pamięci według funkcji. Domyślny widok to Ciężki (od dołu). Pokazuje on funkcje, które przypisano najwięcej pamięci u góry.

Profil alokacji

Wykrywanie częstych operacji czyszczenia pamięci

Jeśli Twoja strona często jest wstrzymywana, może to oznaczać, że występują problemy ze czyszczeniem pamięci.

Częste przypadki czyszczenia pamięci możesz znaleźć w Menedżerze zadań Chrome lub w nagraniach pamięci na osi czasu. W Menedżerze zadań często rosnące i malejące wartości Memory i JavaScript Memory oznaczają częste odśmiecanie pamięci. Na wykresach na osi czasu często rosną i spadające sterty JS lub wykresy liczby węzłów wskazują na częste odczyszczenie pamięci.

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