JavaScript memory management and garbage collection

Low-level languages ​​like C generally have low-level memory management interfaces, such as malloc () and free (). In contrast, JavaScript has an automatic garbage collection mechanism. The execution environment is responsible for managing the memory used during code execution. Memory is automatically allocated when variables (objects, strings, etc.) are created, and "automatically" released when they are not used. The process of release is called garbage collection. This garbage collection mechanism is very simple, find out those variables that are not in use, and then release the memory they occupy. To this end, the garbage collector will periodically perform this operation at fixed intervals (or the scheduled collection time during code execution).

1. The life cycle of local variables

Local variables only exist during the execution of the function. In this process, the corresponding space will be allocated on the stack (or heap) memory for the local variables in order to store their values. Then use these variables in the function until the end of the function execution. After the end, local variables are no longer used, so there is no need to exist, so free their memory for future use.

2. Life cycle of memory

No matter what programming language, the memory life cycle is basically the same:

  1. Allocate the memory you need
  2. Use allocated memory (read, write)
  3. Release \ return when not needed
JavaScript memory allocation
2.1. Initialization of values

In order to prevent programmers from allocating memory, JavaScript completes memory allocation when defining variables.

var n = 123; // 给数值变量分配内存var s = "azerty"; // 给字符串分配内存
var o = {
  a: 1,
  b: null
};
// 给对象及其包含的值分配内存
// 给数组及其包含的值分配内存(就像对象一样)var a = [1, null, "abra"]; 
function f(a){
  return a + 2;
} 
// 给函数(可调用的对象)分配内存
// 函数表达式也能分配一个对象
someElement.addEventListener('click', function(){
  someElement.style.backgroundColor = 'blue';
}, false);
2.2. Allocating memory through function calls

The result of some function calls is to allocate object memory:

var d = new Date(); // 分配一个 Date 对象
var e = document.createElement('div'); // 分配一个 DOM 元素

Some methods assign new variables or new objects:

// s2 是一个新的字符串
// 因为字符串是不变量
// JavaScript 可能决定不分配内存
// 只是存储了 [0-3] 的范围。
var s = "azerty";
var s2 = s.substr(0, 3); 
// 新数组有四个元素,是 a 连接 a2 的结果
var a = ["ouais ouais", "nan nan"];var a2 = ["generation", "nan nan"];var a3 = a.concat(a2); 
2.3. Use value

The process of using values ​​is actually the operation of reading and writing allocated memory. Reading and writing may be writing a variable or an attribute value of an object, or even passing parameters of a function.

2.4. Free when memory is no longer needed

Most memory management issues are at this stage. The most difficult task here is to find "which allocated memory is really no longer needed". It often requires developers to determine which block of memory in the program is no longer needed and free it.
The high-level language interpreter embeds a "garbage collector", its main job is to track the allocation and use of memory, so that when the allocated memory is no longer used, it is automatically released. This can only be an approximate process, because it is impossible to determine whether a block of memory is still needed (cannot be solved by an algorithm).

3. Garbage collection

The problem of automatically finding whether some memory is "no longer needed" as described above cannot be determined. Therefore, garbage collection can only solve the general problems with limitations. This section will explain the necessary concepts and understand the main garbage collection algorithms and their limitations.

3.1. Reference

The garbage collection algorithm mainly relies on the concept of reference. In the context of memory management, if an object has permission to access another object (implicit or explicit), it is called that one object refers to another object. For example, a Javascript object has a reference to its prototype (implicit reference) and a reference to its attributes (explicit reference).
Here, the concept of "object" refers not only to JavaScript objects, but also to function scope (or global lexical scope).

3.2. Reference counting garbage collection

This is the initial garbage collection algorithm. This algorithm defines "whether the object is no longer needed" as "whether the object references it". If no reference points to the object (zero reference), the object will be collected by the garbage collection mechanism. The meaning 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 worth-quoting is 1, if the value is assigned to another variable, then reference The number of times is +1. On the contrary, if the variable containing this value is given another value, the number of times the value is quoted is -1. When the value of this value is 0, it means that there is no variable to use this value. Reclaim the memory space occupied by it. When the garbage collector runs again, it is to free up the space occupied by the values ​​with zero reference times.

// 两个对象被创建,一个作为另一个的属性被引用,另一个被分配给变量o
// 很显然,没有一个可以被垃圾收集
var o = { 
  a: {
    b:2
  }}; 
  
// o2变量是第二个对“这个对象”的引用
var o2 = o; 

// 现在,“这个对象”只有一个o2变量的引用了,“这个对象”的原始引用o已经没有
o = 1; 

// 引用“这个对象”的a属性
// 现在,“这个对象”有两个引用了,一个是o2,一个是oa
var oa = o2.a; 
               
// 虽然最初的对象现在已经是零引用了,可以被垃圾回收了
// 但是它的属性a的对象还在被oa引用,所以还不能回收
o2 = "yo"; 

// a属性的那个对象现在也是零引用了
// 它可以被垃圾回收了
oa = null; 
3.2.1. Restrictions: circular references

Netspace Navigator3.0 used reference counting at the earliest, but soon found a serious problem: circular reference
circular reference refers to the object A contains a pointer to object B, and object B also contains a pointer to object A .
The algorithm has a limitation: it cannot handle circular references. In the following example, two objects are created and referenced to each other, forming a cycle. After they are called, they will leave the scope of the function, so they are no longer useful and can be recycled. However, the reference counting algorithm considers that they all reference each other at least once, so they will not be recycled.

function f(){
  var objectA = new Object();
  var objectB = new Object();
  objectA .a = objectB ; // o 引用 o2
  objectB .a = objectA ; // o2 引用 o
}
f();

In this example, oA and oB refer to each other, that is, the number of references to both objects is 2, after using the counting strategy, oA and oB continue to exist after the function is executed. If this function is called multiple times, it will Causes a large amount of memory not to be recycled, because their number of references will never be 0, but the marking strategy is not a problem

3.2.2. Practical examples

IE 6, 7 uses reference counting to garbage collect DOM objects. This method often causes memory leaks when the object is circularly referenced:

var div;
window.onload = function(){
  div = document.getElementById("myDivElement");
  div.circularReference = div;
  div.lotsOfData = new Array(10000).join("*");
};

In the above example, the circularReference attribute of the myDivElement DOM element references myDivElement, resulting in a circular reference. If this attribute is not explicitly removed or set to null, the reference counted garbage collector will always have at least one reference and will keep the DOM element in memory, even if it is deleted from the DOM tree. If this DOM element has a large amount of data (the above lotOfData attribute), the memory occupied by this data will never be released.

3.3. Mark-sweep algorithm

This algorithm simply defines "whether the object is no longer needed" as "whether the object is available". ,
When the variable into the environment, this variable will be marked as "into the environment", generally can not be released into the environment variable memory occupied, as long as the execution flow into the corresponding environment, you might use it. When the variable leaves the environment, mark it as "Leave the environment".

3.3.1 Marking method:

You can use any method to mark variables, for example, you can flip a special bit to record when a variable enters the environment, or use a variable list of "entering the environment" and a variable list of "leaving the environment" to track which variable It has changed. However, this is not important, the key lies in the strategy adopted.

The garbage collector will mark all variables stored in memory at runtime, and will remove the tags of variables in the environment and variables referenced by variables in the environment. Variables marked after this time will be treated as variables to be deleted, because variables in the environment can no longer access these variables. Finally, the garbage collector completes the memory clearing work, destroys the marked values, and reclaims the memory space occupied by them.

This algorithm assumes that an object called root (in Javascript, the root is a global object) is set. The garbage collector will periodically start from the root, find all objects referenced from the root, and then find the objects referenced by these objects ... From the root, the garbage collector will find all objects that can be obtained and collect all objects that cannot be obtained.

This algorithm is better than the previous one, because "objects with zero references" are always unavailable, but the opposite is not necessarily the case, refer to "cyclic references".
Since 2012, all modern browsers have used the mark-and-sweep garbage collection algorithm. All improvements to the JavaScript garbage collection algorithm are based on the improvement of the mark-and-sweep algorithm, and there is no improvement of the mark-and-sweep algorithm itself and its simplified definition of "is the object no longer needed".

3.3.2 Circular references are no longer a problem

In the above example, after the function call returns, the two objects cannot be obtained from the global object. Therefore, they will be recycled by the garbage collector. The second example is the same, once the div and its event processing can not be obtained from the root, they will be collected by the garbage collector.

3.3.3 Restrictions: Those objects that cannot be queried from the root object will be cleared

Although this is a limitation, in practice we rarely encounter similar situations, so developers are less concerned about the garbage collection mechanism.

4. Performance issues

In all browsers, the garbage collection process can be triggered, but it is not recommended. In IE, call window.CollectGarbage () method will immediately perform garbage collection. In Opera 7 and later, calling window.opera.collect () also starts a garbage collection routine.

5. Memory management

JavaScript generally allocates less available memory to web browsers than desktop applications. This is done for security reasons, the purpose is to prevent the JavaScript web page from running out of all system memory and causing the system to crash. The memory limit problem not only affects the allocation of memory to variables, but also affects the call stack and the number of statements that can be executed simultaneously in a thread.
Ensuring that the least amount of memory is used allows pages to get better performance. The best way to optimize memory usage is to save only the necessary data for the code in execution. Once the data is no longer useful, it is best to release it by setting it to null-this practice is called dereferencing. This approach applies to most global variables and properties of global objects. Local variables are automatically dereferenced when they leave the execution environment.

funtion createPerson(name){
  var localPerson = new Object();
  localPerson.name = name;
  return localPerson;
} 
Var globalPerson = createPerson(‘Nicholas’);
// 手工解除globalPerson 的引用
globalPerson = null;

Dereferencing a value does not mean that the memory occupied by the value is automatically reclaimed. The real effect of dereferencing is to get the value out of the execution environment so that the garbage collector can recycle it the next time it runs.

Reference:
[1]: https: //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Memory_Management
[2]: JavaScript advanced programming (3rd edition) 78-81

Published 5 original articles · Likes0 · Visits 125

Guess you like

Origin blog.csdn.net/forteenBrother/article/details/105352944