Znajdowanie wycieków pamięci JavaScript w Chrome

Stworzyłem bardzo prosty przypadek testowy, który tworzy widok szkieletowy, dołącza obsługę do zdarzenia i tworzy instancje klasy zdefiniowanej przez użytkownika. Wierzę, że klikając przycisk "Usuń" w tej próbce, wszystko zostanie wyczyszczone i nie powinno być wycieków pamięci.

Jsfiddle dla kodu jest tutaj: http://jsfiddle.net/4QhR2/

// scope everything to a function
function main() {

    function MyWrapper() {
        this.element = null;
    }
    MyWrapper.prototype.set = function(elem) {
        this.element = elem;
    }
    MyWrapper.prototype.get = function() {
        return this.element;
    }

    var MyView = Backbone.View.extend({
        tagName : "div",
        id : "view",
        events : {
            "click #button" : "onButton",
        },    
        initialize : function(options) {        
            // done for demo purposes only, should be using templates
            this.html_text = "<input type='text' id='textbox' /><button id='button'>Remove</button>";        
            this.listenTo(this,"all",function(){console.log("Event: "+arguments[0]);});
        },
        render : function() {        
            this.$el.html(this.html_text);

            this.wrapper = new MyWrapper();
            this.wrapper.set(this.$("#textbox"));
            this.wrapper.get().val("placeholder");

            return this;
        },
        onButton : function() {
            // assume this gets .remove() called on subviews (if they existed)
            this.trigger("cleanup");
            this.remove();
        }
    });

    var view = new MyView();
    $("#content").append(view.render().el);
}

main();

Nie jestem jednak pewien, jak użyć profilera Google Chrome, aby zweryfikować, że tak jest w rzeczywistości. Jest gazillion rzeczy, które pojawiają się na migawce profilera sterty i nie mam pojęcia, jak rozkodować to, co dobre/złe. Samouczki, które widziałem na nim do tej pory, albo po prostu mówią mi, żebym "używał profilera migawkowego", albo dają mi bardzo szczegółowy Manifest na temat tego, jak działa cały profiler. Czy można po prostu użyć profilera jako narzędzia, czy naprawdę muszę zrozumieć, w jaki sposób całość została zaprojektowana?

EDIT: tutoriale takie jak te:

Wyciek pamięci Gmail mocowanie

Korzystanie Z DevTools

Reprezentują niektóre z mocniejszych materiałów tam, z tego, co widziałem. Jednak poza wprowadzeniem koncepcji 3 migawki techniki , uważam, że oferują one bardzo niewiele pod względem praktycznej wiedzy (dla początkującego jak ja). Samouczek "Korzystanie z DevTools" nie działa na prawdziwym przykładzie, więc jego niejasny i ogólny koncepcyjny opis rzeczy nie jest zbyt pomocny. Co do "Gmaila" przykład:

więc znalazłeś przeciek. Co teraz?

  • Zbadaj ścieżkę zatrzymywania wycieków obiektów w dolnej połowie panelu Profile

  • Jeśli miejsce alokacji nie może być łatwo wywnioskowane (np. słuchacze zdarzeń):

  • Przyrząd konstruktora obiektu zatrzymującego za pomocą konsoli JS, aby zapisać ślad stosu dla alokacji

  • Używając Zamknięcia? Włącz odpowiednie istniejące flaga (tj. goog.wydarzenia.Słuchacz.ENABLE_MONITORING), aby ustawić właściwość creationStack podczas budowy

Jestem bardziej zdezorientowany po przeczytaniu tego, nie mniej. I znowu, to tylko mówi mi, że mam robić rzeczy, a nie jak to robić. Z mojego punktu widzenia wszystkie informacje są albo zbyt niejasne, albo mają sens tylko dla kogoś, kto już zrozumiał proces.

Niektóre z tych bardziej szczegółowych kwestii zostały poruszone w @Jonathan Naguin ' s answer poniżej.

Author: Community, 2013-10-27

7 answers

Dobrym przepływem pracy, aby znaleźć wycieki pamięci, jest technika trzy migawki , po raz pierwszy wykorzystana przez Loreenę Lee i zespół Gmail do rozwiązania niektórych problemów z pamięcią. Kroki są, ogólnie:

  • Zrób zdjęcie sterty.
  • Rób różne rzeczy.
  • zrób kolejne zdjęcie sterty.
  • Powtórz to samo.
  • zrób kolejne zdjęcie sterty.
  • filtruje obiekty przydzielone pomiędzy migawkami 1 i 2 w widoku "podsumowanie" migawki 3.

Dla Twojego przykładu, ja dostosowano kod, aby pokazać ten proces (można go znaleźć tutaj) opóźniając Tworzenie widoku szkieletowego do momentu kliknięcia przycisku Start. Teraz:

  • Uruchom HTML (zapisany lokalnie z tego adresu ) i Zrób migawkę.
  • Kliknij przycisk Start, aby utworzyć widok.
  • Zrób kolejne zdjęcie.
  • kliknij Usuń.
  • Zrób kolejne zdjęcie.
  • Filtruj obiekty przydzielone między migawkami 1 i 2 w "podsumowaniu migawki 3" widok.

Teraz jesteś gotowy, aby znaleźć wycieki pamięci!

Zauważysz węzły o kilku różnych kolorach. Czerwone węzły nie mają bezpośrednich odniesień z Javascript do nich, ale są żywe, ponieważ są częścią oddzielonego drzewa DOM. W drzewie może znajdować się węzeł odwołujący się do Javascript (może jako zamknięcie lub zmienna), ale przypadkowo uniemożliwia zbieranie śmieci przez całe drzewo DOM.

Tutaj wpisz opis obrazka

Żółte węzły mają jednak bezpośrednie odwołania z Javascript. Poszukaj żółtych węzłów w tym samym oddzielonym drzewie DOM, aby zlokalizować odwołania z twojego Javascript. Powinien istnieć łańcuch właściwości prowadzący z okna DOM do elementu.

W twoim konkretnym możesz zobaczyć element HTML div oznaczony jako czerwony. Jeśli rozwiń element, zobaczysz, że jest odwołany przez funkcję "cache".

Tutaj wpisz opis obrazka

Wybierz wiersz i w konsoli wpisz $0, zobaczysz rzeczywistą funkcję i lokalizacja:

>$0
function cache( key, value ) {
        // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
        if ( keys.push( key += " " ) > Expr.cacheLength ) {
            // Only keep the most recent entries
            delete cache[ keys.shift() ];
        }
        return (cache[ key ] = value);
    }                                                     jquery-2.0.2.js:1166

To jest miejsce, gdzie twój element jest odwołany. Niestety niewiele można zrobić, jest to wewnętrzny mechanizm z jQuery. Ale, dla celów testowych, przejdź do funkcji i zmień metodę na:

function cache( key, value ) {
    return value;
}

Teraz, jeśli powtórzysz proces, nie zobaczysz żadnego czerwonego węzła :)

Dokumentacja:

 181
Author: Jonathan Naguin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-01 12:37:21

Oto wskazówka na temat profilowania pamięci jsfiddle: Użyj następującego adresu URL, aby wyizolować wynik jsfiddle, usuwa on wszystkie ramy jsfiddle i ładuje tylko wynik.

Http://jsfiddle.net/4QhR2/show/

Nigdy nie byłem w stanie dowiedzieć się, jak używać osi czasu i profilera do śledzenia wycieków pamięci, dopóki nie przeczytałem poniższej dokumentacji. Po przeczytaniu sekcji "Object allocation tracker" mogłem skorzystać z narzędzia "Record Heap Allocations" , i wyśledzić kilka odłączonych węzłów DOM.

Naprawiłem problem poprzez przejście z wiązania zdarzeń jQuery na delegowanie zdarzeń szkieletowych. Rozumiem, że nowsze wersje Backbone automatycznie odpiszą zdarzenia, jeśli wywołasz View.remove(). Wykonaj niektóre dema samodzielnie, są one skonfigurowane z wyciekami pamięci, które możesz zidentyfikować. Nie krępuj się zadawać pytań tutaj, jeśli nadal nie rozumiesz tego po przestudiowaniu tego dokumentacja.

Https://developers.google.com/chrome-developer-tools/docs/javascript-memory-profiling

 6
Author: ricksuggs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-01 13:55:08

Zasadniczo musisz spojrzeć na liczbę obiektów wewnątrz Twojej migawki sterty. Jeśli liczba obiektów zwiększy się między dwoma migawkami, a obiekty zostaną usunięte, wystąpi wyciek pamięci. Moja rada polega na tym, aby w Twoim kodzie znaleźć procedury obsługi zdarzeń, które nie zostaną odłączone.

 5
Author: Konstantin Dinev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-27 17:33:30

Możesz też przeczytać:

Http://addyosmani.com/blog/taming-the-unicorn-easing-javascript-memory-profiling-in-devtools/

Wyjaśnia korzystanie z narzędzi programistycznych chrome i daje kilka wskazówek krok po kroku, jak potwierdzić i zlokalizować wyciek pamięci za pomocą porównania migawek sterty i różnych dostępnych widoków migawek hep.

 3
Author: bennidi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-15 09:56:43

Jest film wprowadzający od Google, który będzie bardzo pomocny w znalezieniu wycieków pamięci JavaScript.

Https://www.youtube.com/watch?v=L3ugr9BJqIs

 3
Author: 令狐葱,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-14 07:59:59

Możesz również spojrzeć na zakładkę oś czasu w narzędziach programistycznych. Rejestruj korzystanie z aplikacji i miej oko na węzeł DOM i liczbę detektorów zdarzeń.

Jeśli Wykres pamięci rzeczywiście wskazuje wyciek pamięci, możesz użyć profilera, aby dowiedzieć się, co wycieka.

 2
Author: Robert Falkén,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-30 08:35:52

[1]}popieram radę, aby zrobić migawkę sterty, są doskonałe do wykrywania wycieków pamięci, chrome robi świetną robotę snapshotting.

W moim projekcie badawczym dla mojego stopnia budowałem interaktywną aplikację internetową, która musiała generować wiele danych wbudowanych w "warstwy", wiele z tych warstw zostanie "usuniętych" w interfejsie użytkownika, ale z jakiegoś powodu pamięć nie była dealokowana, za pomocą narzędzia migawki byłem w stanie ustalić, że JQuery trzymał odniesienie na stronie. obiekt (źródło było wtedy, gdy próbowałem wywołać zdarzenie .load(), które utrzymywało odniesienie pomimo wyjścia poza zakres). Mając te informacje pod ręką samodzielnie zapisałem mój projekt, jest to bardzo przydatne narzędzie, gdy korzystasz z bibliotek innych ludzi i masz ten problem z utrzymywaniem odniesień powstrzymujących GC od wykonywania swojej pracy.

Edytuj: Warto również zaplanować z wyprzedzeniem, jakie działania zamierzasz wykonać, aby zminimalizować czas spędzony na robieniu zdjęć, hipotezować, co może być przyczyną problem i przetestuj każdy scenariusz, tworząc migawki przed i po.

 2
Author: ProgrammerInProgress,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-06 09:26:41