Heim >Web-Frontend >js-Tutorial >Lernen Sie den Garbage-Collection-Mechanismus und die Speicherverwaltung von JavaScript mit me_javascript-Kenntnissen

Lernen Sie den Garbage-Collection-Mechanismus und die Speicherverwaltung von JavaScript mit me_javascript-Kenntnissen

WBOY
WBOYOriginal
2016-05-16 15:30:331244Durchsuche

1. Garbage-Collection-Mechanismus – GC

Javascript verfügt über einen automatischen Garbage-Collection-Mechanismus (GC: Garbage Collection), was bedeutet, dass die Ausführungsumgebung für die Verwaltung des während der Codeausführung verwendeten Speichers verantwortlich ist.

Prinzip: Der Garbage Collector findet regelmäßig (periodisch) die Variablen heraus, die nicht mehr verwendet werden, und gibt dann ihren Speicher frei.

Der Mechanismus der JavaScript-Garbage Collection ist sehr einfach: Finden Sie die Variablen, die nicht mehr verwendet werden, und geben Sie dann den von ihnen belegten Speicher frei. Dieser Prozess erfolgt jedoch nicht in Echtzeit, da sein Overhead relativ groß ist, so der Garbage Collector folgt dem festen Zeitplan Wird regelmäßig in einem bestimmten Zeitintervall ausgeführt .

Variablen, die nicht mehr verwendet werden, sind Variablen, deren Lebenszyklus beendet ist. Natürlich können sie nur lokale Variablen sein. Der Lebenszyklus globaler Variablen endet erst, wenn der Browser die Seite entlädt. Lokale Variablen existieren nur während der Ausführung der Funktion. Während dieses Vorgangs wird den lokalen Variablen auf dem Stapel oder Heap entsprechender Speicherplatz zugewiesen, um ihre Werte zu speichern. Anschließend werden diese Variablen in der Funktion bis zum Ende der Funktion verwendet , und der Abschluss Aufgrund interner Funktionen im Paket können externe Funktionen nicht als Ende betrachtet werden.

Erklären wir den Code:

function fn1() {
 var obj = {name: 'hanzichi', age: 10};
}

function fn2() {
 var obj = {name:'hanzichi', age: 10};
 return obj;
}

var a = fn1();
var b = fn2();

Sehen wir uns an, wie der Code ausgeführt wird. Zunächst werden zwei Funktionen mit den Namen fn1 bzw. fn2 definiert. Wenn fn1 aufgerufen wird, wird beim Betreten der Umgebung von fn1 ein Speicher geöffnet, um das Objekt {Name: 'hanzichi', Alter: 10} zu speichern Wenn die fn1-Umgebung abgeschlossen ist, wird dieser Speicherblock während des Aufrufs von fn2 automatisch vom Garbage Collector in der js-Engine freigegeben. Die globale Variable b zeigt auf das zurückgegebene Objekt, sodass dieser Speicherblock angezeigt wird nicht freigegeben werden.

Hier stellt sich die Frage: Welche Variable ist nutzlos? Daher muss der Garbage Collector im Auge behalten, welche Variablen nutzlos sind, und Variablen markieren, die nicht mehr nützlich sind, um sie auf die zukünftige Rückgewinnung ihres Speichers vorzubereiten. Die zum Markieren nicht verwendeter Variablen verwendete Strategie kann von Implementierung zu Implementierung variieren, im Allgemeinen gibt es jedoch zwei Implementierungen: Mark-Sweeping und Referenzzählung. Referenzzählung wird seltener verwendet, Mark-and-Sweep wird häufiger verwendet.

2. Markierung löschen

Die am häufigsten verwendete Garbage-Collection-Methode in js ist das Markieren. Wenn eine Variable in die Umgebung gelangt, beispielsweise durch die Deklaration einer Variablen in einer Funktion, wird die Variable als „in die Umgebung eingetreten“ markiert. Logischerweise kann der von Variablen, die in die Umgebung gelangen, belegte Speicher niemals freigegeben werden, da sie immer dann verwendet werden können, wenn der Ausführungsfluss in die entsprechende Umgebung eintritt. Und wenn eine Variable die Umgebung verlässt, wird sie als „die Umgebung verlassen“ markiert.

function test(){
 var a = 10 ; //被标记 ,进入环境 
 var b = 20 ; //被标记 ,进入环境
}
test(); //执行完毕 之后 a、b又被标离开环境,被回收。

Wenn der Garbage Collector ausgeführt wird, markiert er alle im Speicher gespeicherten Variablen (natürlich kann jede Markierungsmethode verwendet werden). Anschließend werden die Tags (Abschlüsse) von Variablen in der Umgebung und Variablen, auf die Variablen in der Umgebung verweisen, entfernt. Variablen, die danach markiert werden, werden als zu löschende Variablen betrachtet, da Variablen in der Umgebung nicht mehr auf diese Variablen zugreifen können. Schließlich führt der Garbage Collector die Speicherbereinigung durch, indem er die markierten Werte zerstört und den von ihnen belegten Speicherplatz zurückgewinnt.

Bisher verwenden alle js-Implementierungen von IE, Firefox, Opera, Chrome und Safari Mark-and-Sweep-Garbage-Collection-Strategien oder ähnliche Strategien, aber die Zeitintervalle für die Garbage-Collection sind unterschiedlich.

3. Referenzanzahl

Die Bedeutung der Referenzzählung besteht darin, zu verfolgen, wie oft auf jeden Wert verwiesen wird. Wenn eine Variable deklariert und der Variablen ein Referenztypwert zugewiesen wird, beträgt die Anzahl der Referenzen auf diesen Wert 1. Wenn derselbe Wert einer anderen Variablen zugewiesen wird, wird der Referenzzähler des Werts um 1 erhöht. Wenn umgekehrt die Variable, die einen Verweis auf diesen Wert enthält, einen anderen Wert erhält, wird die Anzahl der Verweise auf diesen Wert um eins dekrementiert. Wenn die Anzahl der Verweise auf diesen Wert 0 wird, bedeutet dies, dass es keine Möglichkeit mehr gibt, auf diesen Wert zuzugreifen, sodass der von ihm belegte Speicherplatz zurückgewonnen werden kann. Auf diese Weise gibt der Garbage Collector bei der nächsten Ausführung den Speicher frei, der von diesen Werten mit einem Referenzzähler von 0 belegt wird.

function test(){
 var a = {} ; //a的引用次数为0 
 var b = a ; //a的引用次数加1,为1 
 var c =a; //a的引用次数再加1,为2
 var b ={}; //a的引用次数减1,为1
}

Netscape Navigator3 war der erste Browser, der die Referenzzählstrategie verwendete, stieß jedoch bald auf ein ernstes Problem: Zirkelverweise. Ein Zirkelverweis bedeutet, dass Objekt A einen Zeiger auf Objekt B enthält und Objekt B auch einen Verweis auf Objekt A enthält.

function fn() {
 var a = {};
 var b = {};
 a.pro = b;
 b.pro = a;
}

fn();

  以上代码a和b的引用次数都是2,fn()执行完毕后,两个对象都已经离开环境,在标记清除方式下是没有问题的,但是在引用计数策略下,因为a和b的引用次数不为0,所以不会被垃圾回收器回收内存,如果fn函数被大量调用,就会造成内存泄露。在IE7与IE8上,内存直线上升。

我们知道,IE中有一部分对象并不是原生js对象。例如,其内存泄露DOM和BOM中的对象就是使用C++以COM对象的形式实现的,而COM对象的垃圾回收机制采用的就是引用计数策略。因此,即使IE的js引擎采用标记清除策略来实现,但js访问的COM对象依然是基于引用计数策略的。换句话说,只要在IE中涉及COM对象,就会存在循环引用的问题。

var element = document.getElementById("some_element");
var myObject = new Object();
myObject.e = element;
element.o = myObject;

  这个例子在一个DOM元素(element)与一个原生js对象(myObject)之间创建了循环引用。其中,变量myObject有一个名为element的属性指向element对象;而变量element也有一个属性名为o回指myObject。由于存在这个循环引用,即使例子中的DOM从页面中移除,它也永远不会被回收。

看上面的例子,有同学回觉得太弱了,谁会做这样无聊的事情,其实我们是不是就在做

window.onload=function outerFunction(){
 var obj = document.getElementById("element");
 obj.onclick=function innerFunction(){};
};

这段代码看起来没什么问题,但是obj引用了document.getElementById(“element”),而document.getElementById(“element”)的onclick方法会引用外部环境中德变量,自然也包括obj,是不是很隐蔽啊。

解决办法

最简单的方式就是自己手工解除循环引用,比如刚才的函数可以这样

myObject.element = null;
element.o = null;


window.onload=function outerFunction(){
 var obj = document.getElementById("element");
 obj.onclick=function innerFunction(){};
 obj=null;
};

Das Setzen einer Variablen auf Null bedeutet, dass die Verbindung zwischen der Variablen und dem Wert, auf den sie zuvor verwiesen hat, getrennt wird. Wenn der Garbage Collector das nächste Mal ausgeführt wird, werden diese Werte entfernt und der von ihnen belegte Speicher wird zurückgefordert.

Es ist zu beachten, dass IE9 nicht das Problem eines durch Zirkelverweise verursachten Dom-Speicherverlusts hat. Es kann sein, dass Microsoft Optimierungen vorgenommen hat oder sich die Art und Weise, wie Dom recycelt wird, geändert hat

4. Speicherverwaltung

1. Wann wird die Speicherbereinigung ausgelöst?

Der Garbage Collector wird regelmäßig ausgeführt, wenn viel Speicher zugewiesen wird. Die Bestimmung des Garbage Collection-Intervalls ist eine Überlegung wert. Die Garbage Collection von IE6 wird basierend auf der Speicherzuweisung ausgeführt, wenn in der Umgebung 256 Variablen, 4096 Objekte oder 64.000 Zeichenfolgen vorhanden sind. Es sieht sehr wissenschaftlich aus und es besteht keine Notwendigkeit, einen Absatz zu drücken. Es wird jedes Mal nur einmal aufgerufen, manchmal ist es nicht notwendig. Wäre es nicht schön, es bei Bedarf anzurufen? Aber wenn es so viele Variablen in der Umgebung gibt und das Skript jetzt so komplex ist, ist es normal, dass der Garbage Collector immer funktioniert, sodass der Browser nicht abspielen kann.

Microsoft hat in IE7 Anpassungen vorgenommen. Die Auslösebedingungen sind nicht mehr festgelegt, sondern dynamisch geändert. Der Anfangswert ist derselbe wie in IE6, wenn die vom Garbage Collector wiederhergestellte Speicherzuweisungsmenge weniger als 15 % des belegten Speichers beträgt Laut Programm bedeutet dies, dass der größte Teil des Speichers nicht recycelt werden kann. Zu diesem Zeitpunkt ist der Wert des recycelten Speichers zu hoch Der Speicher sollte vor langer Zeit bereinigt werden. Setzen Sie die Triggerbedingung zurück. Dies erleichtert die Garbage-Collection-Funktion erheblich

2. Angemessener GC-Plan

1) Die grundlegende GC-Lösung der Javascript-Engine ist (einfache GC): Markieren und Sweepen, das heißt:

  • (1) Durchqueren Sie alle zugänglichen Objekte.
  • (2) Recyceln Sie Objekte, auf die nicht mehr zugegriffen werden kann.

2), GC-Defekte

Wie bei anderen Sprachen kann auch die GC-Strategie von JavaScript ein Problem nicht vermeiden: Während der GC reagiert es aus Sicherheitsgründen nicht mehr auf andere Vorgänge. Der GC von Javascript beträgt 100 ms oder mehr, was für allgemeine Anwendungen in Ordnung ist, aber für JS-Spiele und Animationsanwendungen, die eine relativ hohe Kontinuität erfordern, ist es problematisch. Das ist es, was die neue Engine optimieren muss: um lange Reaktionspausen durch GC zu vermeiden.

3), GC-Optimierungsstrategie

Onkel David hat hauptsächlich zwei Optimierungspläne eingeführt, und dies sind auch die beiden wichtigsten Optimierungspläne:

(1) Generation GC (Generation GC)
Dies steht im Einklang mit der Idee der Java-Recyclingstrategie. Der Zweck besteht darin, zwischen „temporären“ und „persistenten“ Objekten zu unterscheiden; mehr „temporäre Objekt“-Bereiche (junge Generation) und weniger „persistente Objekt“-Bereiche (Tenur-Generation) zu recyceln, um die Anzahl der Objekte zu reduzieren, die jedes Mal durchlaufen werden müssen Dadurch wird der Zeitaufwand für jeden GC reduziert. Wie im Bild gezeigt:

Was hier hinzugefügt werden muss, ist: Für Objekte der Tenured-Generation entsteht ein zusätzlicher Aufwand: Die Migration von der jungen Generation zur Tenured-Generation muss außerdem geändert werden, wenn darauf verwiesen wird.

(2) Inkrementelle GC
Die Idee dieser Lösung ist sehr einfach: „Jedes Mal ein wenig verarbeiten, beim nächsten Mal ein wenig verarbeiten und so weiter.“ Wie im Bild gezeigt:

Obwohl diese Lösung nur kurze Zeit in Anspruch nimmt, weist sie viele Unterbrechungen auf und bringt das Problem eines häufigen Kontextwechsels mit sich.

Da jede Lösung ihre anwendbaren Szenarien und Mängel aufweist, wird die Lösung in tatsächlichen Anwendungen basierend auf der tatsächlichen Situation ausgewählt.

Zum Beispiel: Wenn das (Objekt/s)-Verhältnis niedrig ist, ist die Häufigkeit der Interrupt-Ausführung von GC geringer, und wenn eine große Anzahl von Objekten über einen längeren Zeitraum „überlebt“, ist die Häufigkeit von Generationen geringer Die Verarbeitung ist nicht so toll.

Referenz:

Das Obige dreht sich alles um den Garbage-Collection-Mechanismus und die Speicherverwaltung von JavaScript. Ich hoffe, dass es für das Lernen aller hilfreich sein wird.

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn