Garbage collection mechanism

We know that there will be some garbage data in the program that is no longer used and needs to be released in time. If we do not release it in time, it is a memory leak

Garbage data in JS is collected by Garbage Collection (short for GC) automatically without manual release.

Very simple, the JS engine has a background process called garbage collector, it monitors all objects, observe whether objects are accessible, and then periodically delete those objects that are not accessible at a fixed interval

There are two methods of garbage collection commonly used by browsers today:

  • Reference counting
  • Mark clear

#### Reference count

The earliest and simplest garbage collection mechanism is to attach a reference counter to an object that occupies physical space. When the object is referenced by another object, the reference count of the object is increased by one. Otherwise, the reference count of the object is decreased by one.

This is simple, but causes memory leaks:

// Problem with circular references
function temp(){
    var a={};
    var b={};
    a.o = b;
    b.o = a;
}
Copy the code

In this case, the reference count of a and B is 2 each time the temp function is called, so that the memory will never be freed, that is, the memory leaks. It is now rarely used, only with lower versions of Internet Explorer.

Mark clear

The main garbage collector in V8 uses the tag sweep method for garbage collection. The main process is as follows:

  • Flags: Traverses the call stack to see if objects in the old generation region heap are referenced. The referenced objects are marked as live objects and the unreferenced objects (to be cleaned up) are marked as garbage data.
  • Garbage cleanup: Clean up all garbage data

(Leaks: How JavaScript Works: Memory Management + How to Handle 4 Common Memory)

During our development, if we want the garbage collector to reclaim an object, we set the object’s reference directly to NULL

var a = {}; // {} is accessible, and a is its reference

a = null; // Reference is set to null
// {} will be cleared from memory
Copy the code

However, if an object is referenced multiple times, such as as a key, value, or child element of another object, and the object reference is set to NULL, the object will not be reclaimed and will still exist

var a = {}; 
var arr = [a];

a = null; 
console.log(arr)
/ / ({})
Copy the code

What if it’s called a Map?

var a = {}; 
var map = new Map(a); map.set(a,'Three-minute learning front end')

a = null; 
console.log(map.keys()) // MapIterator {{}}
console.log(map.values()) // MapIterator {" 3 minutes learning front-end "}
Copy the code

What if you want the object to be reclaimed when a is set to null?

WeakMap vs Map

With this in mind, ES6 introduced WeakMap. Its references to values are not garbage collected, which is why it has an “Weak” in its name, indicating that it is Weak. (Weak references to objects do not prevent the GC from collecting them when they should be collected.)

Map relative to WeakMap:

  • MapCan be of any type,WeakMapOnly objects (except null) are accepted as keys, and values of other types are not accepted as keys
  • MapThe key is actually bound to the memory address, as long as the memory address is different, as two keys;WeakMapThe key is a weak reference, and the object the key points to can be garbage collected, in which case the key is invalid
  • MapCan be traversed,WeakMapCannot be traversed

Let’s take WeakMap as an example to see how it causes the above problems:

var a = {}; 
var map = new WeakMap(a); map.set(a,'Three-minute learning front end')
map.get(a)

a = null; 
Copy the code

What does the above example not show? Let’s test with process.memoryUsage:

//map.js
global.gc(); // 0 each memory query is performed first by gc() followed by memoryUsage() to ensure garbage collection and ensure that the obtained memoryUsage status is accurate

function usedSize() {
    const used = process.memoryUsage().heapUsed;
    return Math.round((used / 1024 / 1024) * 100) / 100 + "M";
}

console.log(usedSize()); // 1 Initial state, heapUsed is 1.64m after GC () and memoryUsage()

var map = new Map(a);var b = new Array(5 * 1024 * 1024);

map.set(b, 1);

global.gc();
console.log(usedSize()); // 2 After adding element B into the Map, which is an array of 5*1024*1024, heapUsed is about 41.82M

b = null;
global.gc();

console.log(usedSize()); // 3 After b is set to null, heapUsed is still 41.82M, indicating that the 5*1024*1024 array in Map still exists
Copy the code

Run the node –expose-gc map.js command:

The — expose-GC parameter allows manual garbage collection

// weakmap.js
function usedSize() {
    const used = process.memoryUsage().heapUsed;
    return Math.round((used / 1024 / 1024) * 100) / 100 + "M";
}

global.gc(); // 0 each memory query is performed first by gc() followed by memoryUsage() to ensure garbage collection and ensure that the obtained memoryUsage status is accurate
console.log(usedSize()); // 1 Initial state, heapUsed is 1.64m after GC () and memoryUsage()
var map = new WeakMap(a);var b = new Array(5 * 1024 * 1024);

map.set(b, 1);

global.gc();
console.log(usedSize()); // 2 After adding element B into the Map, which is an array of 5*1024*1024, heapUsed is about 41.82M

b = null;
global.gc();

console.log(usedSize()); // 3 After b is set to null, heapUsed becomes about 1.82m, indicating that the array with length of 5*1024*1024 in WeakMap is destroyed
Copy the code

Execute node — expose-GC weakmap.js command:

In the above code, as long as the external reference disappears, the internal reference of WeakMap will be automatically cleared by garbage collection. So, with its help, fixing memory leaks is a lot easier.

Finally, take a look at WeakMap

WeakMap

A WeakMap object is a collection of key-value pairs, where the keys are weak reference objects and the values can be arbitrary.

Note that WeakMap weakly references only the key name, not the key value. Key values are still normal references.

In WeakMap, the reference of each key to its referenced object is weak. If there is no other reference and the key references the same object, the object will be garbage collected (the corresponding key becomes invalid). Therefore, the key of WeakMap is not enumerable.

Properties:

  • Constructor: a constructor

Methods:

  • Has (key) : checks whether there is an object associated with the key
  • Get (key) : returns the object associated with the key (undefined)
  • Set (key) : Sets a group of key associated objects
  • Delete (key) : deletes the object associated with the key
let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap(a); myWeakmap.set(myElement, {timesClicked: 0});

myElement.addEventListener('click'.function() {
  let logoData = myWeakmap.get(myElement);
  logoData.timesClicked++;
}, false);
Copy the code

WeakMap and WeakSet are weak references, which can be recovered by garbage collection mechanism and can be used to save DOM nodes, which is not easy to cause memory leakage

In addition, there is the WeakRef of ES12. If you are interested, you can know that it is too late tonight, and it will be updated later

reference

You don’t know WeakMap

Three minutes a day