Co to jest czyszczenie pamięci JavaScript? Co jest ważne dla programisty internetowego, aby rozumieć zbieranie śmieci JavaScript w celu napisania lepszego kodu?
Co to jest czyszczenie pamięci JavaScript? Co jest ważne dla programisty internetowego, aby rozumieć zbieranie śmieci JavaScript w celu napisania lepszego kodu?
Odpowiedzi:
Eric Lippert napisał jakiś szczegółowy blog na ten temat jakiś czas temu (dodatkowo porównując go do VBScript ). Dokładniej napisał o JScript , który jest własną implementacją ECMAScript Microsoftu, chociaż bardzo podobną do JavaScript. Wyobrażam sobie, że można założyć, że zdecydowana większość zachowań byłaby taka sama dla silnika JavaScript przeglądarki Internet Explorer. Oczywiście implementacja będzie się różnić w zależności od przeglądarki, ale podejrzewam, że możesz wziąć wiele wspólnych zasad i zastosować je w innych przeglądarkach.
Cytat z tej strony:
JScript korzysta z nieenereneracyjnego zbieracza śmieci typu mark-and-sweep. Działa to tak:
Każda zmienna, która jest „w zasięgu”, nazywana jest „wymiataczem”. Zmiatacz może odnosić się do liczby, obiektu, łańcucha, cokolwiek innego. Prowadzimy listę zmiataczy - zmienne są przenoszone na listę zmiatania, gdy wchodzą w zakres, i z listy, gdy wychodzą z zakresu.
Od czasu do czasu działa śmietnik. Najpierw umieszcza „znak” na każdym obiekcie, zmiennej, łańcuchu itp. - całej pamięci śledzonej przez GC. (JScript korzysta wewnętrznie ze struktury danych VARIANT i jest w niej wiele dodatkowych nieużywanych bitów, więc właśnie ustawiliśmy jeden z nich.)
Po drugie, usuwa ślad na padlinożercach i przechodnie przechodzenie odniesień do padlinożerców. Więc jeśli obiekt zmiatający odwołuje się do obiektu nieużywającego, wówczas usuwamy bity na nienaśmiecającym i na wszystkim, do czego się odnosi. (Używam słowa „zamknięcie” w innym znaczeniu niż w moim wcześniejszym poście).
W tym momencie wiemy, że cała pamięć wciąż zaznaczona to pamięć przydzielona, do której nie można dotrzeć żadną ścieżką z żadnej zmiennej in-scope. Wszystkie te obiekty mają się rozerwać, co niszczy wszelkie okrągłe odniesienia.
Głównym celem wyrzucania elementów bezużytecznych jest to, aby programiści nie martwili się zarządzaniem pamięcią obiektów, które tworzą i używają, choć oczywiście czasami nie da się tego uniknąć - zawsze dobrze jest mieć przynajmniej ogólne pojęcie o działaniu wyrzucania elementów bezużytecznych .
Uwaga historyczna: wcześniejsza wersja odpowiedzi zawierała niepoprawne odniesienie do delete
operatora. W JavaScript operator usuwa własności z przedmiotu i jest całkowicie inny niż C / C ++.delete
delete
delete
nieprawidłowo; np. w pierwszym przykładzie, zamiast delete foo
, należy najpierw usunąć detektor zdarzeń za pomocą, window.removeEventListener()
a następnie użyć foo = null
do zastąpienia zmiennej; w IE delete window.foo
(ale nie delete foo
) również działałby, gdyby foo
był globalny, ale nawet wtedy nie działałby w FF i Operze
delete
jest jednoargumentowym operatorem (wyrażenie), a nie instrukcją (tj .:) delete 0, delete 0, delete 3
. Wygląda jak instrukcja wyrażona przez wyrażenie wyrażeniowe.
Uwaga na odnośniki cykliczne, gdy w grę wchodzą obiekty DOM:
Wzorce wycieków pamięci w JavaScript
Pamiętaj, że pamięć można odzyskać tylko wtedy, gdy nie ma aktywnych odniesień do obiektu. Jest to częsta pułapka w przypadku zamknięć i procedur obsługi zdarzeń, ponieważ niektóre silniki JS nie sprawdzają, które zmienne są faktycznie przywoływane w funkcjach wewnętrznych, a jedynie zachowują wszystkie zmienne lokalne funkcji zamykających.
Oto prosty przykład:
function init() {
var bigString = new Array(1000).join('xxx');
var foo = document.getElementById('foo');
foo.onclick = function() {
// this might create a closure over `bigString`,
// even if `bigString` isn't referenced anywhere!
};
}
Naiwna implementacja JS nie może się zbierać, bigString
dopóki istnieje moduł obsługi zdarzeń. Istnieje kilka sposobów rozwiązania tego problemu, np. Ustawienie bigString = null
na końcu init()
( delete
nie działa dla zmiennych lokalnych i argumentów funkcji: delete
usuwa właściwości z obiektów, a obiekt zmiennej jest niedostępny - ES5 w trybie ścisłym wyrzuci nawet ReferenceError
jeśli spróbujesz usunąć zmienną lokalną!).
Zalecam unikanie niepotrzebnego zamykania, jeśli zależy Ci na zużyciu pamięci.
Dobry cytat z bloga
Składnik DOM jest „odśmiecany”, podobnie jak składnik JScript, co oznacza, że jeśli utworzysz obiekt w którymkolwiek z komponentów, a następnie stracisz kontakt z tym obiektem, zostanie on ostatecznie wyczyszczony.
Na przykład:
function makeABigObject() {
var bigArray = new Array(20000);
}
Po wywołaniu tej funkcji komponent JScript tworzy obiekt (o nazwie bigArray), który jest dostępny w obrębie funkcji. Gdy jednak funkcja powróci, „tracisz orientację” bigArray, ponieważ nie ma już możliwości odwoływania się do niego. Cóż, komponent JScript zdaje sobie sprawę, że go zgubiłeś, a więc bigArray został oczyszczony - jego pamięć została odzyskana. To samo działa w komponencie DOM. Jeśli powiesz document.createElement('div')
lub coś podobnego, komponent DOM tworzy dla Ciebie obiekt. Gdy w jakiś sposób stracisz kontakt z tym obiektem, komponent DOM wyczyści powiązane.
Zgodnie z moją najlepszą wiedzą, obiekty JavaScript są okresowo usuwane, gdy nie ma żadnych odwołań do obiektu. Jest to coś, co dzieje się automatycznie, ale jeśli chcesz dowiedzieć się więcej o tym, jak to działa, na poziomie C ++ warto spojrzeć na kod źródłowy WebKit lub V8
Zazwyczaj nie trzeba o tym myśleć, jednak w starszych przeglądarkach, takich jak IE 5.5 i wczesne wersje IE 6, i być może w obecnych wersjach, zamknięcia tworzyłyby cykliczne odwołania, które po odznaczeniu powodowałyby zużycie pamięci. W konkretnym przypadku, który mam na myśli w przypadku zamknięć, było to wtedy, gdy dodałeś odwołanie JavaScript do obiektu dom i obiekt do obiektu DOM, który odwoływał się z powrotem do obiektu JavaScript. Zasadniczo nigdy nie można go było zebrać, co ostatecznie spowodowałoby niestabilność systemu operacyjnego w aplikacjach testowych, które zapętlały się w celu utworzenia awarii. W praktyce przecieki te są zwykle niewielkie, ale aby utrzymać kod w czystości, należy usunąć odwołanie JavaScript do obiektu DOM.
Zwykle dobrym pomysłem jest użycie słowa kluczowego delete, aby natychmiast odwołać odwołanie do dużych obiektów, takich jak dane JSON, które otrzymałeś i zrobić wszystko, co musisz z tym zrobić, szczególnie w tworzeniu aplikacji mobilnych. Powoduje to, że następny przegląd GC usunie ten obiekt i zwolni jego pamięć.
mark-and-sweep
algorytmy stylu tym zająć .
odśmiecanie pamięci (GC) jest formą automatycznego zarządzania pamięcią poprzez usuwanie niepotrzebnych już obiektów.
każdy proces zajmujący się pamięcią wykonaj następujące kroki:
1 - przydziel potrzebne miejsce w pamięci
2 - wykonaj przetwarzanie
3 - zwolnij to miejsce w pamięci
istnieją dwa główne algorytmy do wykrywania, które obiekty nie są już potrzebne.
Wyrzucanie elementów bezużytecznych : ten algorytm redukuje definicję „obiekt nie jest już potrzebny” do „obiekt nie ma innego obiektu, do którego się odwołuje”, obiekt zostanie usunięty, jeśli nie ma do niego punktu odniesienia
Algorytm oznaczania i przeciągania : podłącz każdy obiekt do źródła root. żaden obiekt nie łączy się z rootem ani innym obiektem. ten obiekt zostanie usunięty.
obecnie większość nowoczesnych przeglądarek używa drugiego algorytmu.
„W informatyce wyrzucanie elementów bezużytecznych (GC) jest formą automatycznego zarządzania pamięcią. Moduł wyrzucania elementów bezużytecznych, lub po prostu moduł zbierający, próbuje odzyskać elementy wyrzucające śmieci lub pamięć wykorzystywaną przez obiekty, do których aplikacja nigdy nie uzyska dostępu ani nie zostanie zmutowana”.
Wszystkie silniki JavaScriptu mają własne urządzenia do zbierania śmieci i mogą się różnić. Przez większość czasu nie musisz sobie z nimi radzić, ponieważ robią to, co powinni.
Pisanie lepszego kodu zależy głównie od tego, jak dobrze znasz zasady programowania, język i konkretną implementację.
Co to jest czyszczenie pamięci JavaScript?
sprawdź to
Co jest ważne dla programisty internetowego, aby rozumieć zbieranie śmieci JavaScript w celu napisania lepszego kodu?
W Javascript nie przejmujesz się przydziałem i dezalokacją pamięci. Cały problem jest wymagany od interpretera Javascript. Wycieki są nadal możliwe w JavaScript, ale są to błędy interpretera. Jeśli jesteś zainteresowany tym tematem, możesz przeczytać więcej na www.memorymanagement.org
W systemie Windows możesz użyć narzędzia Drip.exe, aby znaleźć wycieki pamięci lub sprawdzić, czy działa darmowa procedura mem.
To naprawdę proste, wystarczy wpisać adres URL strony, a zobaczysz zużycie pamięci przez zintegrowany renderer IE. Następnie naciśnij przycisk odświeżania, jeśli pamięć się zwiększy, zauważyłeś wyciek pamięci gdzieś na stronie internetowej. Ale jest to również bardzo przydatne, aby sprawdzić, czy procedury zwalniania pamięci działają w IE.
Typy referencyjne nie przechowują obiektu bezpośrednio w zmiennej, do której jest przypisany, więc zmienna obiektowa w tym przykładzie tak naprawdę nie zawiera instancji obiektu. Zamiast tego zawiera wskaźnik (lub odniesienie) do miejsca w pamięci, w którym istnieje obiekt
var object = new Object();
jeśli przypiszesz jedną zmienną do drugiej, każda zmienna otrzyma kopię wskaźnika i obie nadal będą odwoływać się do tego samego obiektu w pamięci.
var object1 = new Object();
var object2 = object1;
JavaScript jest językiem zbierającym śmieci , więc tak naprawdę nie musisz martwić się o przydział pamięci podczas korzystania z typów referencyjnych. Jednak najlepiej wyrejestrować obiekty, których już nie potrzebujesz, aby śmieciarz mógł zwolnić tę pamięć. Najlepszym sposobem na to jest ustawienie zmiennej obiektowej na null.
var object1 = new Object();
// do something
object1 = null; // dereference
Obiekty dereferencyjne są szczególnie ważne w bardzo dużych aplikacjach, które wykorzystują miliony obiektów.
z zasad JavaScript obiektowego - NICHOLAS C. ZAKAS