Stworzyłem bardzo prosty przypadek testowy, który tworzy widok Backbone, dołącza procedurę obsługi do zdarzenia i tworzy instancję klasy zdefiniowanej przez użytkownika. Uważam, że po kliknięciu przycisku „Usuń” w tym przykładzie wszystko zostanie wyczyszczone i nie powinno być żadnych wycieków pamięci.
Plik 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 mam jednak pewności, jak używać profilera Google Chrome, aby sprawdzić, czy tak jest w rzeczywistości. Jest miliard rzeczy, które pojawiają się na migawce programu profilującego sterty i nie mam pojęcia, jak rozszyfrować, co jest dobre, a co złe. Samouczki, które widziałem do tej pory, albo po prostu mówią mi, żebym „użył profilera migawek”, albo podają bardzo szczegółowy manifest na temat działania całego profilera. Czy można po prostu użyć programu profilującego jako narzędzia, czy naprawdę muszę zrozumieć, jak wszystko zostało zaprojektowane?
EDYCJA: Poradniki takie jak te:
Naprawianie wycieku pamięci w Gmailu
Są reprezentatywne dla niektórych silniejszych materiałów, z tego, co widziałem. Jednak poza przedstawieniem koncepcji 3 Snapshot Technique , uważam, że oferują one bardzo mało praktycznej wiedzy (dla początkującego takiego jak ja). Samouczek „Korzystanie z narzędzi dla programistów” nie opiera się na prawdziwym przykładzie, więc jego niejasny i ogólny koncepcyjny opis rzeczy nie jest zbyt pomocny. Jeśli chodzi o przykład „Gmail”:
Więc znalazłeś wyciek. Co teraz?
Sprawdź ścieżkę mocowania przecieków w dolnej połowie panelu Profile
Jeśli nie można łatwo wywnioskować lokalizacji alokacji (tj. Nasłuchiwania zdarzeń):
Instrumentuj konstruktora obiektu przechowującego za pośrednictwem konsoli JS, aby zapisać ślad stosu dla alokacji
Używasz zamknięcia? Włącz odpowiednią istniejącą flagę (np. Goog.events.Listener.ENABLE_MONITORING), aby ustawić właściwość createStack podczas tworzenia
Po przeczytaniu tego jestem bardziej zdezorientowany, a nie mniej. I znowu, po prostu mówi mi, żebym coś robił , a nie jak to robić. Z mojej perspektywy wszystkie dostępne informacje są albo zbyt niejasne, albo miałyby sens tylko dla kogoś, kto już zrozumiał ten proces.
Niektóre z tych bardziej szczegółowych kwestii zostały poruszone w odpowiedzi @Jonathana Naguina poniżej.
źródło
main
10000 razy zamiast jednego razu i sprawdzenie, czy na końcu zostanie użytych dużo więcej pamięci.Odpowiedzi:
Dobrym sposobem na znalezienie wycieków pamięci jest technika trzech migawek , po raz pierwszy zastosowana przez Loreenę Lee i zespół Gmaila do rozwiązania niektórych problemów z pamięcią. Ogólnie kroki są następujące:
Na przykład dostosowałem kod, aby pokazać ten proces (możesz go znaleźć tutaj ), opóźniając tworzenie widoku szkieletu do momentu kliknięcia przycisku Start. Teraz:
Teraz jesteś gotowy, aby znaleźć wycieki pamięci!
Zauważysz węzły o kilku różnych kolorach. Węzły czerwone nie mają bezpośrednich odwołań z JavaScript do nich, ale są żywe, ponieważ są częścią odłączonego drzewa DOM. W drzewie może znajdować się węzeł, do którego odwołuje się kod JavaScript (może to być zamknięcie lub zmienna), ale przypadkowo uniemożliwia to zebranie elementów bezużytecznych w całym drzewie DOM.
Jednak żółte węzły mają bezpośrednie odniesienia z JavaScript. Poszukaj żółtych węzłów w tym samym odłączonym drzewie DOM, aby zlokalizować odwołania z JavaScript. Powinien istnieć łańcuch właściwości prowadzący od okna DOM do elementu.
W szczególności możesz zobaczyć element HTML Div oznaczony na czerwono. Jeśli rozwiniesz element, zobaczysz, że odwołuje się do niego funkcja „cache”.
Wybierz wiersz iw konsoli wpisz $ 0, zobaczysz aktualną funkcję i lokalizację:
Tutaj znajduje się odniesienie do Twojego elementu. Niestety niewiele można zrobić, jest to wewnętrzny mechanizm z jQuery. Ale dla celów testowych przejdź do funkcji i zmień metodę na:
Teraz, jeśli powtórzysz proces, nie zobaczysz żadnego czerwonego węzła :)
Dokumentacja:
źródło
$0
funkcji w konsoli, która była dla mnie nowa - oczywiście nie mam pojęcia, co to robi ani skąd wiedziałeś, jak go używać ($1
wydaje się bezużyteczne, podczas gdy$2
wydaje się robić to samo). Po drugie, skąd wiedziałeś, że należy wyróżnić wiersz,#button in function cache()
a nie którykolwiek z pozostałych dziesiątek wierszy? Wreszcie pojawiają się czerwone węzłyNodeList
iHTMLInputElement
też, ale nie mogę ich rozgryźć.cache
wiersz zawiera informacje, a pozostałe nie? Istnieje wiele gałęzi, które mają mniejszą odległość niż tacache
. I nie jestem pewien, skąd wiedziałeś, żeHTMLInputElement
jest dzieckiemHTMLDivElement
. Widzę, że odwołuje się do niego w środku („natywny w HTMLDivElement”), ale odwołuje się również do siebie i dwóchHTMLButtonElement
, co nie ma dla mnie sensu. Z pewnością doceniam, że podałeś odpowiedź na ten przykład, ale naprawdę nie miałbym pojęcia, jak uogólnić to na inne kwestie.Filter objects allocated between Snapshots 1 and 2 in Snapshot 3's "Summary" view.
znaczy?Oto wskazówka dotycząca profilowania pamięci jsfiddle: Użyj następującego adresu URL, aby wyodrębnić wynik jsfiddle, usuwa on całą strukturę jsfiddle i ładuje tylko twój 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 zatytułowanej „Śledzenie alokacji obiektów” udało mi się użyć narzędzia „Rejestruj alokacje sterty” i śledzić kilka odłączonych węzłów DOM.
Rozwiązałem problem, przełączając się z wiązania zdarzeń jQuery na delegowanie zdarzeń Backbone. Rozumiem, że nowsze wersje Backbone automatycznie usuwają powiązania wydarzeń, jeśli zadzwonisz
View.remove()
. Wykonaj samodzielnie niektóre dema, są one skonfigurowane z wyciekami pamięci, które możesz zidentyfikować. Jeśli po przestudiowaniu tej dokumentacji nadal nie otrzymasz odpowiedzi, możesz zadawać pytania.https://developers.google.com/chrome-developer-tools/docs/javascript-memory-profiling
źródło
Zasadniczo musisz przyjrzeć się liczbie obiektów wewnątrz migawki sterty. Jeśli liczba obiektów wzrośnie między dwoma migawkami i pozbyłeś się obiektów, masz wyciek pamięci. Radzę poszukać w swoim kodzie programów obsługi zdarzeń, które nie są odłączane.
źródło
Window/http://jsfiddle.net/4QhR2/show
może się przydać, ale to tylko nieskończone funkcje. Nie mam pojęcia, co się tam dzieje.Istnieje film wprowadzający od Google, który będzie bardzo pomocny w wyszukiwaniu wycieków pamięci JavaScript.
https://www.youtube.com/watch?v=L3ugr9BJqIs
źródło
Możesz również spojrzeć na kartę Oś czasu w narzędziach programistycznych. Rejestruj użycie swojej aplikacji i miej oko na liczbę węzłów DOM i odbiorników zdarzeń.
Jeśli wykres pamięci rzeczywiście wskazywałby na wyciek pamięci, możesz użyć profilera, aby dowiedzieć się, co przecieka.
źródło
Możesz także przeczytać:
http://addyosmani.com/blog/taming-the-unicorn-easing-javascript-memory-profiling-in-devtools/
Wyjaśnia użycie narzędzi deweloperskich chrome i podaje kilka porad 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.
źródło
Popieram radę, aby zrobić migawkę sterty, są doskonałe do wykrywania wycieków pamięci, chrome świetnie radzi sobie z migawkami.
W moim projekcie badawczym na stopień naukowy budowałem interaktywną aplikację internetową, która musiała generować dużo danych zgromadzonych w „warstwach”, wiele z tych warstw zostanie „usuniętych” w interfejsie użytkownika, ale z jakiegoś powodu pamięć nie po zwolnieniu przydziału, za pomocą narzędzia do tworzenia migawek byłem w stanie określić, że JQuery zachowywał odniesienie do obiektu (źródło było, gdy próbowałem wyzwolić
.load()
zdarzenie, które zachowało odniesienie pomimo wyjścia poza zakres). Mając te informacje pod ręką, samodzielnie zapisując mój projekt, jest to bardzo przydatne narzędzie, gdy używasz bibliotek innych osób i masz problem z utrzymującymi się referencjami, które uniemożliwiają GC wykonywanie swojej pracy.EDYCJA: Warto również zaplanować z wyprzedzeniem, jakie czynności zamierzasz wykonać, aby zminimalizować czas spędzony na tworzeniu migawek, postawić hipotezę, co może być przyczyną problemu i przetestować każdy scenariusz, wykonując migawki przed i po.
źródło
Kilka ważnych uwag dotyczących identyfikowania wycieków pamięci za pomocą narzędzi Chrome Developer:
1) Sam Chrome ma wycieki pamięci dla niektórych elementów, takich jak hasła i pola liczbowe. https://bugs.chromium.org/p/chromium/issues/detail?id=967438 . Unikaj używania ich podczas debugowania, ponieważ sprawdzają one migawkę sterty podczas wyszukiwania odłączonych elementów.
2) Unikaj rejestrowania czegokolwiek w konsoli przeglądarki. Chrome nie zbiera śmieci zapisanych na konsoli, co wpływa na wynik. Możesz wyłączyć wyjście, umieszczając następujący kod na początku skryptu / strony:
3) Użyj migawek sterty i wyszukaj „odłącz”, aby zidentyfikować odłączone elementy DOM. Umieszczając kursor na obiektach, uzyskujesz dostęp do wszystkich właściwości, w tym id i externalHTML, które mogą pomóc w identyfikacji każdego elementu. Jeśli odłączone elementy są nadal zbyt ogólne, aby je rozpoznać, przed uruchomieniem testu przypisz im unikalne identyfikatory za pomocą konsoli przeglądarki, np .:
Teraz, gdy zidentyfikujesz odłączony element za pomocą, powiedzmy id = "AutoId_49", załaduj ponownie stronę, ponownie wykonaj powyższy fragment i znajdź element z id = "AutoId_49" za pomocą inspektora DOM lub document.querySelector (..) . Oczywiście działa to tylko wtedy, gdy zawartość strony jest przewidywalna.
Jak przeprowadzam testy, aby zidentyfikować wycieki pamięci
1) Załaduj stronę (z wyłączonym wyjściem konsoli!)
2) Rób na stronie rzeczy, które mogą spowodować wycieki pamięci
3) Użyj narzędzi deweloperskich, aby wykonać migawkę sterty i wyszukać „odłącz”
4) Najedź na elementy, aby zidentyfikować je na podstawie ich właściwości id lub externalHTML
źródło