Memory mechanism

The data structure

The stack

“LIFO”

The heap

A heap is an unordered tree structure that can be retrieved directly by key-value

The queue

Fifo data structure, the basic structure of the JS engine Event Loop

JS variable storage

  1. Basic types: The basic types are stored in the stack structure, these types occupy a fixed size of memory, by value access, ES6 has 6 basic types, undefined, NULL, Boolean, number, string, symbol, ES9 added bigInt
  2. Reference type: stored in the heap memory, because the size of this value is not fixed, so it cannot be stored in the stack, so it is stored in the heap memory, the reference to its address is stored in the stack memory, when the variable is queried, first find the reference address in the stack, and then extract the specific value in the heap according to the address, access by reference

The stack is faster than the heap, and the reference structure is placed in the heap so as not to affect stack execution efficiency.

Jane about the closure

Closure variables are not stored in the stack, but in the heap, which is why closures can always keep references to internal variables of functions

Memory space management

The memory life cycle of JS is:

  1. Allocate the required memory
  2. Use allocated memory
  3. Release it when it’s not needed

Js itself has its own garbage collection algorithm, garbage collection will be automatically, variables declared in local variables, when the function is finished, it is not needed naturally, but in the global environment declared variables, it is difficult to make a judgment when to release, so we should try to avoid using global variables

Reference sample

var a = {n: 1};
var b = a;
a.x = a = {n: 2};

a.x 	// undefined
b.x 	// {n: 2}
Copy the code
  1. A is declared as an object
  2. Assign a to B, and B keeps a reference to A
  3. .A.x = {n:1,x:undefined}
  4. {n:2} is assigned to a, so the final value of A is {n:2}.
  5. A.x = {n: 1, x: undefined} b.x = {n: 1, x: undefined}

Garbage collection algorithm

Reference counting (no longer used in modern browsers)

Reference counting algorithm is very simple, is to see whether an object has a point to its reference, if there are no other object pointing to it, means that the object is no longer need the reference count is a fatal problem, it is a circular reference, if two objects refer to each other, so the garbage collection will decide if keep reference, instead of recycling, thus may lead to memory leaks

Mark clear

The tag clearing algorithm defines “no longer used object” as “unreachable object”. Start from the root (JS global object) to periodically scan the objects in memory, all objects that can be reached from the root are retained, if not, they are marked as no longer in use, and recycled later. Therefore, for mainstream browsers now, only need to cut the connection between the object that needs to be recycled and the root. The most common memory leaks are associated with DOM element bindings (for example, if an object is bound to a DOM element and the DOM element is deleted later, but the DOM remains in memory because the object is bound).

Garbage collection mechanism under V8

New generation algorithm

The Cenozoic exploiture is based on the Scavenge GC algorithm. In the new generation space, the memory space is divided into two parts, namely From and To space. Of these two Spaces, one must be used and the other free. The newly allocated objects are put into the From, and when the From space is full, the new generation GC starts. The algorithm checks for viable objects in the From space and copies them To the To space, and destroys deactivated objects. When the copy is complete, the From and To Spaces are swapped, and the GC ends

Old generation algorithm

The objects in the old generation generally live for a long time and have a large number. Two algorithms are used, namely, the mark clearing algorithm and the mark compression algorithm

Before we get to the algorithms, we need to explain how objects are created in the old age space: whether an object from the new generation has been scinsane, and if so, moved from the new generation to the old. The size of objects in the To space exceeds 25%. In this case, objects are moved from the new generation space to the old generation space in order not to affect memory allocation.

In the old generation, the tag clearing algorithm is started in the following cases:

  • When there is no partition of a space
  • The object in space exceeds a limit
  • Space does not guarantee that objects in the new generation will move into the old generation

Object removal will cause heap memory fragmentation, when the fragmentation exceeds a certain limit will start the compression algorithm. During compression, live objects are moved on one side until all objects have been moved and unneeded memory is cleared.

Common memory leaks

1. Unexpected global variables

Undefined variables create a new variable globally

function foo(arg) {
    bar = "bar";
}
Copy the code

The function defines variables internally, without using let or var, causing JS to mount bar to the global variable, window.bar = ‘bar’

It could also be created through this

function foo() {
    this.variable = "variable";
}

// Foo calls itself, this refers to the global object (window)
// instead of undefined
// So in this case, unexpected global variables can also result
foo();
Copy the code

Solutions:

Add ‘use strict’ to the header of your JavaScript file, using strict mode to avoid unexpected global variables, in which case this points to undefined. If you must use a global variable to store a lot of data, be sure to set it to NULL or redefine it when you’re done using it.

2. The timer is not cleared

Timers such as setTimeout and setInterval, if uninstalled, will survive even if the Node Node is gone unless uninstalled

setInterval(function() {
    var node = document.getElementById('Node');
    // Other processing. },1000);
Copy the code

It is important for AddeventListeners to explicitly remove them once they are no longer needed (or the associated object becomes unreachable). Old IE 6 couldn’t handle circular references. Older versions of IE were unable to detect cyclic references between DOM nodes and JavaScript code, leading to memory leaks.

However, modern browsers (including Internet Explorer and Microsoft Edge) use more advanced garbage collection algorithms (tag sweep) that already detect and handle circular references correctly. You don’t have to call removeEventListener to reclaim node memory

var element = document.getElementById('button');
function onClick(event) {
    element.innerHTML = 'text';
}

element.addEventListener('click', onClick);
Copy the code

3. References to DOM

If you store the DOM as a dictionary (JSON key-value pairs) or an array, the same DOM element has two references: one in the DOM tree and one in the dictionary. Both references will need to be cleared in the future.

var elements = {
    button: document.getElementById('button'),
    image: document.getElementById('image'),
    text: document.getElementById('text')};// elements dictionary. The button element is still in memory and cannot be collected by GC
document.body.removeChild(document.getElementById('button'));
Copy the code

4, closures

Closure effect will lead to lasting some variables stored in the memory, such as our classic application of singleton pattern, closure variables in reference, because the cause of the scope chain, will remain persistent references, so the closure variables are put in the heap memory, during the closure to keep for reference variable is kept, so it is easy to cause memory leaks

function MyModal(){}

MyModal.getInstance = (function(){
    let instance = null;
    return function(){
        if(! instance){ instance =new MyModal();
        }
        return instance
    }
})()
Copy the code