JS garbage collection mechanism

JS automatically allocates memory when creating variables and periodically frees memory when it is not in use. This process is called “garbage collection”. There are good and bad sides to this mechanism. On the one hand, automatic memory allocation relieves the burden of developers, who do not have to pay too much attention to memory usage, but on the other hand, because of automatic reclamation, if the mechanism of reclamation is not clear, it is easy to cause confusion, and confusion is easy to cause “memory leak “. Because it is automatic recycling, so there is a “memory need to be recycled” problem, but the determination of this problem in the program means that it cannot be solved accurately and completely through an algorithm, the recycling mechanism discussed later can only be limited to solve the general problem.

Recovery algorithm

The problem of whether garbage collection pairs need to be collected depends mainly on whether variables are accessible or not, thus two main collection algorithms are derived:

  • Mark sweep
  • Reference counting

Mark sweep

Tag cleaning is the most common js recycling strategy, which has been used by all browsers since 2012, and subsequent improvements to the recycling policy are based on this policy. The strategy is:

  1. A variable enters a context, also known as a scope, marked to prove that it exists in that context;
  2. Remove all variables in the context and variables referenced by access in the context to indicate that these variables are active and useful;
  3. Variables tagged after this point are marked as variables ready for deletion because they are no longer accessible by variables in context;
  4. Perform a memory cleanup, destroying all marked inactive values and reclaiming previously occupied memory;

limited

  • Since the search starts from the root object (the global object), objects that cannot be queried from the root object are cleared
  • Memory fragments are generated after reclamation, affecting large contiguous memory space

Reference counting

Reference counting strategies are relatively uncommon because of their drawbacks. The idea is to record the number of times that each value is referenced, and decide whether to keep it or not by judging the number of times (the number of references is 0). The specific rules are as follows

  • When declaring a variable and assigning it a reference value, count +1;
  • When the same value is assigned to another variable, reference +1;
  • The variable that holds a reference to this value is overwritten by another value, reference -1;
  • Reference to 0, reclaim memory;

limited

The most important problem is the problem of circular references

function refProblem () {
	let a = new Object(a);let b = new Object(a); a.c = b; b.c = a;// cross-reference
}
Copy the code

According to the rules mentioned earlier, both variables reference each other and the reference count is not zero, so neither variable can be reclaimed. If the change function is called frequently, it can cause a serious memory leak.

Nodejs V8 recycling mechanism

V8’s reclamation mechanism is based on generational reclamation. Memory is divided into the young generation and the tenured generation. The young generation is the object that has a short lifetime, and the old generation is the variable that has a long lifetime or is resident in memory.

V8 stack composition

V8 divides the heap into several different areas

  • New Space/Young Generation: Most of the New Generation are allocated here and are divided into two Spaces that take up a small Space as a whole. The recycling algorithm is Scavenge

  • Old Space/Old Generation: Most of the objects that live in the nascent area for a period of time are moved here, using a mark-sweep & Mark-Compact (Major GC) algorithm, which is subdivided into two Spaces

    • Old pointer space: stores objects that have Pointers to other objects
    • Old data space: Stored objects contain only data and have no Pointers to other objects
  • Large Object Space: Stores Large objects that exceed the limits of other Spaces. The garbage collector never moves objects in this Space

  • Code, Code Space: Space objects, used for storing Code, is the only have execute permission of memory Space, it is important to note if the Code object is too large to be moved to large object Space, the object Code is in large object Space have execute permissions, but not so large object Space also have execute permissions

  • Cell Space,Property Space,Map Space (Cell,Property,Map Space) : These areas store cells,Property cells, and maps. Each Space stores elements of the same size, so the memory structure is simple.

Scavenge algorithm

The Scavenge algorithm is the primary algorithm in the New generation space. It was developed by C.J. Cheney in 1970 in his paper A Nonrecursive list Compacting Algorithm. Scavenge is based on the Cheney algorithm. The Cheney algorithm divides the heap memory of the new generation space into two blocks of the same size called Semi space, the ones in use are called From space and the ones unused are called To space. The garbage collection process is as follows:

  • Check the From space. If the From space is allocated full, recycle the garbage using the Scavenge algorithm
  • If the space is not fully allocated, it checks whether there are any living objects in the From space. If there are no living objects, it directly frees the space of the non-living objects
  • If the object survives, it will be checked whether it meets the promotion conditions. If it meets the promotion conditions, it will be moved To the old generation space; otherwise, the object will be copied To the To space
  • After the replication is complete, the roles of the From and To Spaces will be reversed, and then the execution will start From the first step

Promotion condition

  1. Be Scavenge;
  2. To space memory usage exceeds 25%;

Mark-sweep & Mark-Compact (Major GC) algorithm

As mentioned before, the marker-clearing strategy will cause memory fragmentation, which will affect the memory usage. The emergence of marker-compact algorithm can solve this problem well. The mark-sweep algorithm is a variation of mark-sweep, which moves active objects to the edge and then clears inactive objects when the move is complete.

This is slower than Mark-sweep because you need to move objects.

Stop The World

To prevent the application logic from being different from what the garbage collector sees, the garbage collector stops the application logic during the collection and continues the application logic after the collection task is completed. This behavior is a total pause, depending on how long it takes different engines to perform a garbage collection. This kind of pause has little effect on Cenozoic space, but may cause pause phenomenon to old generation space.

Incremental Marking

To address total pauses, V8 2011 introduced incremental markers. V8 breaks down the tagging process into sub-tagging processes, alternating garbage collection tagging and JS application logic until tagging is complete.

A memory leak

Memory leaks are difficult to detect and can be a big problem when functions are called many times. There are several common scenarios for memory leaks.

Accidentally declare global variables

function hello(a){
	name = 'tom'
}
hello();
Copy the code

Undeclared objects are bound to global objects and will not be reclaimed if they are not used, so always declare variables when writing code.

The timer

let name = 'Tom';
setInterval(() = > {
  console.log(name);
}, 100);
Copy the code

Timer callbacks refer to external variables through closures. If the timer is not cleared, the name will always use memory, so it is a good idea to know what variables you need when using a timer, check the variables inside the timer, and remember to clear the timer if you do not use it.

closure

let out = function() {
  let name = 'Tom';
  return function () {
    console.log(name); }}Copy the code

Since the closure is resident in memory, in this example, if out is always present, the name is never cleaned up, and if the name value is very large, it causes a serious memory leak. So be careful with closures.

Event listeners

mounted() {
window.addEventListener("resize".() = > {
	//do something
});
}
Copy the code

Event listeners are bound when the page is initialized, but are not cleared when the page leaves, resulting in a memory leak.

The last

This article is a summary of the reference notes article, I recently re-learn JS, will review the summary of the article recorded in Github, jab here, want to review the partner can participate in the review summary together!

The resources

  1. Interesting Node.js memory leak
  2. Js garbage collection mechanism
  3. A tour of V8: Garbage Collection
  4. JS Exploration -GC garbage collection
  5. JavaScript Memory Management
  6. JavaScript Advanced Programming (version 4)