Heim  >  Artikel  >  Web-Frontend  >  Umfassendes Verständnis des Garbage-Collection-Mechanismus von JavaScript_Grundkenntnisse

Umfassendes Verständnis des Garbage-Collection-Mechanismus von JavaScript_Grundkenntnisse

亚连
亚连Original
2018-05-19 16:39:30952Durchsuche

Jetzt werde ich Ihnen ein umfassendes Verständnis des Garbage-Collection-Mechanismus von JavaScript vermitteln. Lassen Sie mich es jetzt mit Ihnen teilen und es allen als Referenz geben.

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 verantwortlich ist Der in Codeausführungsprozess verwendete Speicher.

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 er teuer ist, also den Müll Der Kollektor folgt dem festen In einem bestimmten Zeitintervall regelmäßig 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.

Lass uns den Code erklären:

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

Lass uns sehen, 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, und 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. Markierungslöschung

Die am häufigsten verwendete Speicherbereinigungsmethode in js ist die Markierungslöschung. 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 Speicher, der von Variablen belegt wird, die in eine Umgebung gelangen, 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又被标离开环境,被回收。

Der Garbage Collector markiert alle im Speicher gespeicherten Variablen, wenn er ausgeführt wird (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 Garbage-Collection-Intervalle sind unterschiedlich.

3. Referenzzählung

Die Bedeutung der Referenzzählung besteht darin, die Anzahl der Referenzen auf jeden Wert zu verfolgen und aufzuzeichnen. 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();

Die Referenzzeiten der obigen Codes a und b sind beide 2. Nach der Ausführung von fn() haben beide Objekte die Umgebung verlassen. Es gibt kein Problem im Markierungs- und Löschmodus, aber unter der Referenz Zählstrategie: Da die Anzahl der Verweise auf a und b nicht 0 ist, wird der Speicher vom Garbage Collector nicht zurückgefordert. Wenn die fn-Funktion eine große Zahl aufruft, führt dies zu einem Speicherverlust. Unter IE7 und IE8 schoss der Speicher sprunghaft in die Höhe.

我们知道,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;
};

将变量设置为null意味着切断变量与它此前引用的值之间的连接。当垃圾回收器下次运行时,就会删除这些值并回收它们占用的内存。

要注意的是,IE9+并不存在循环引用导致Dom内存泄露问题,可能是微软做了优化,或者Dom的回收方式已经改变

四、内存管理

1、什么时候触发垃圾回收?

垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。IE6的垃圾回收是根据内存分配量运行的,当环境中存在256个变量、4096个对象、64k的字符串任意一种情况的时候就会触发垃圾回收器工作,看起来很科学,不用按一段时间就调用一次,有时候会没必要,这样按需调用不是很好吗?但是如果环境中就是有这么多变量等一直存在,现在脚本如此复杂,很正常,那么结果就是垃圾回收器一直在工作,这样浏览器就没法儿玩儿了。

微软在IE7中做了调整,触发条件不再是固定的,而是动态修改的,初始值和IE6相同,如果垃圾回收器回收的内存分配量低于程序占用内存的15%,说明大部分内存不可被回收,设的垃圾回收触发条件过于敏感,这时候把临街条件翻倍,如果回收的内存高于85%,说明大部分内存早就该清理了,这时候把触发条件置回。这样就使垃圾回收工作职能了很多

2、合理的GC方案

1)、Javascript引擎基础GC方案是(simple GC):mark and sweep(标记清除),即:

  • (1)遍历所有可访问的对象。

  • (2)回收已不可访问的对象。

2)、GC的缺陷

和其他语言一样,javascript的GC策略也无法避免一个问题:GC时,停止响应其他操作,这是为了安全考虑。而Javascript的GC在100ms甚至以上,对一般的应用还好,但对于JS游戏,动画对连贯性要求比较高的应用,就麻烦了。这就是新引擎需要优化的点:避免GC造成的长时间停止响应。

3)、GC优化策略

David大叔主要介绍了2个优化方案,而这也是最主要的2个优化方案了:

(1)分代回收(Generation GC)

这个和Java回收策略思想是一致的。目的是通过区分“临时”与“持久”对象;多回收“临时对象”区(young generation),少回收“持久对象”区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时。如图:

这里需要补充的是:对于tenured generation对象,有额外的开销:把它从young generation迁移到tenured generation,另外,如果被引用了,那引用的指向也需要修改。

(2)增量GC
这个方案的思想很简单,就是“每次处理一点,下次再处理一点,如此类推”。如图:

这种方案,虽然耗时短,但中断较多,带来了上下文切换频繁的问题。

因为每种方案都其适用场景和缺点,因此在实际应用中,会根据实际情况选择方案。

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.

Das Obige habe ich für Sie zusammengestellt und hoffe, dass es Ihnen in Zukunft hilfreich sein wird.

Verwandte Artikel:

Javascript-Erstellung von Klassen und Objekten (Bild- und Text-Tutorial)

Detaillierte Erklärung der JavaScript-Pfeilfunktion (Bild ) Text-Tutorial)

Ausführliche Antwort darauf in JavaScript (Grafik-Tutorial)

Das obige ist der detaillierte Inhalt vonUmfassendes Verständnis des Garbage-Collection-Mechanismus von JavaScript_Grundkenntnisse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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