Home  >  Article  >  Web Front-end  >  Learn JavaScript’s garbage collection mechanism and memory management from me_javascript skills

Learn JavaScript’s garbage collection mechanism and memory management from me_javascript skills

WBOY
WBOYOriginal
2016-05-16 15:30:331217browse

1. Garbage collection mechanism—GC

Javascript has an automatic garbage collection mechanism (GC: Garbage Collection), which means that the execution environment is responsible for managing the memory used during code execution.

Principle: The garbage collector will periodically (periodically) find out those variables that are no longer in use, and then release their memory.

The mechanism of JavaScript garbage collection is very simple: find the variables that are no longer used, and then release the memory they occupy. However, this process is not real-time because its overhead is relatively large, so the garbage collector will follow the fixed schedule Execute periodically at a certain time interval .

Variables that are no longer used are variables whose life cycle has ended. Of course, they can only be local variables. The life cycle of global variables will not end until the browser unloads the page. Local variables only exist during the execution of the function, and during this process, corresponding space will be allocated for local variables on the stack or heap to store their values, and then these variables will be used in the function until the end of the function, and the closure Due to internal functions in the package, external functions cannot be considered the end.

Let’s explain the 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();

Let’s see how the code is executed. First, two functions are defined, called fn1 and fn2 respectively. When fn1 is called, entering the environment of fn1, a memory will be opened to store the object {name: 'hanzichi', age: 10}, and when the call is completed, the fn1 environment, then this block of memory will be automatically released by the garbage collector in the js engine; during the process of fn2 being called, the returned object is pointed to by the global variable b, so this block of memory will not be released.

The question arises here: Which variable is useless? Therefore, the garbage collector must keep track of which variables are useless and mark variables that are no longer useful to prepare for reclaiming their memory in the future. The strategy used for marking unused variables may vary from implementation to implementation, but generally there are two implementations: mark-sweeping and reference counting. Reference counting is less commonly used, mark-and-sweep is more commonly used.

2. Mark clearing

The most commonly used garbage collection method in js is mark clearing. When a variable enters the environment, for example, by declaring a variable in a function, the variable is marked as "entered the environment." Logically, the memory occupied by variables entering the environment can never be released, since they may be used whenever the execution flow enters the corresponding environment. And when a variable leaves the environment, it is marked as "leaving the environment".

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

When the garbage collector runs, it will mark all variables stored in memory (of course, any marking method can be used). Then, it removes the tags (closures) of variables in the environment and variables referenced by variables in the environment. Variables that are marked after this will be regarded as variables to be deleted because variables in the environment can no longer access these variables. Finally, the garbage collector completes the memory cleanup work, destroying those marked values ​​and reclaiming the memory space they occupy.

So far, the js implementations of IE, Firefox, Opera, Chrome, and Safari all use mark-and-sweep garbage collection strategies or similar strategies, but the garbage collection time intervals are different.

3. Reference Count

The meaning of reference counting is to track the number of times each value is referenced. When a variable is declared and a reference type value is assigned to the variable, the number of references to this value is 1. If the same value is assigned to another variable, the reference count of the value is increased by 1. Conversely, if the variable containing a reference to this value obtains another value, the number of references to this value is decremented by one. When the number of references to this value becomes 0, it means that there is no way to access this value anymore, so the memory space it occupies can be reclaimed. In this way, when the garbage collector runs next time, it will release the memory occupied by those values ​​​​with a reference count of 0.

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 was the first browser to use the reference counting strategy, but soon it encountered a serious problem: circular references. A circular reference means that object A contains a pointer to object B, and object B also contains a reference to object A.

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;
};

Setting a variable to null means severing the connection between the variable and the value it previously referenced. The next time the garbage collector runs, these values ​​are removed and the memory they occupy is reclaimed.

It should be noted that IE9 does not have the problem of Dom memory leak caused by circular references. It may be that Microsoft has made optimizations or the way Dom is recycled has changed

4. Memory Management

1. When is garbage collection triggered?

The garbage collector runs periodically. If a lot of memory is allocated, the recycling work will be very arduous. Determining the garbage collection interval becomes a question worth thinking about. IE6's garbage collection runs based on the amount of memory allocation. When there are 256 variables, 4096 objects, or 64k strings in the environment, the garbage collector will be triggered. It looks very scientific, and there is no need to press a paragraph. It's only called once every time, sometimes it's not necessary, wouldn't it be nice to call it on demand? But if there are so many variables in the environment and the script is so complex now, it is normal, then the result is that the garbage collector is always working, so the browser cannot play.

Microsoft has made adjustments in IE7. The trigger conditions are no longer fixed, but dynamically modified. The initial value is the same as IE6. If the memory allocation amount recovered by the garbage collector is less than 15% of the memory occupied by the program, it means Most of the memory cannot be recycled. The set trigger condition for garbage collection is too sensitive. At this time, double the street condition. If the recycled memory is higher than 85%, it means that most of the memory should be cleaned up long ago. At this time, set the trigger condition back. . This makes the garbage collection function a lot easier

2. Reasonable GC plan

1) The basic GC solution of Javascript engine is (simple GC): mark and sweep, that is:

  • (1) Traverse all accessible objects.
  • (2) Recycle objects that are no longer accessible.

2), GC defects

Like other languages, JavaScript’s GC strategy cannot avoid a problem: during GC, it stops responding to other operations. This is for security reasons. The GC of Javascript is 100ms or more, which is fine for general applications, but for JS games and animation applications that require relatively high continuity, it is troublesome. This is what the new engine needs to optimize: to avoid long pauses in response caused by GC.

3), GC optimization strategy

Uncle David mainly introduced 2 optimization plans, and these are also the two most important optimization plans:

(1) Generation GC (Generation GC)
This is consistent with the idea of ​​Java recycling strategy. The purpose is to distinguish between "temporary" and "persistent" objects; recycle more "temporary object" areas (young generation) and less "persistent object" areas (tenured generation) to reduce the number of objects that need to be traversed each time, thereby reducing each GC time consuming. As shown in the picture:

What needs to be added here is: for tenured generation objects, there is additional overhead: migrating it from the young generation to the tenured generation. In addition, if it is referenced, the reference point also needs to be modified.

(2) Incremental GC
The idea of ​​​​this solution is very simple, that is, "process a little bit each time, and then process a little bit next time, and so on." As shown in the picture:

Although this solution takes a short time, it has many interruptions and brings about the problem of frequent context switching.

Because each solution has its applicable scenarios and shortcomings, in actual applications, the solution will be selected based on the actual situation.

For example: when the (object/s) ratio is low, the frequency of interrupt execution GC is lower, and simple GC is lower; if a large number of objects "survive" for a long time, the advantage of generational processing is not great.

Reference:

The above is all about the garbage collection mechanism and memory management of JavaScript. I hope it will be helpful to everyone's learning.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn