The browser’s Garbage Collection, or GC, runs periodically to free up unwanted memory; otherwise, the JavaScript interpreter will run out of system memory, causing the system to crash.

Implementations in the browser typically have two policies: tag cleanup and reference counting.

Reference counting

This algorithm simplifies the definition of “is the object no longer needed” to “has the object been referenced by other objects”. If there is no reference to the object (zero reference), the object is collected by the garbage collection mechanism.

let car = { logo: 'luhu', price: 100} // jeep is the first reference to this object. Let jeep = car // jeep is the second reference to this object. Car Jeep = null // jeep is set to null that object is zero reference can be reclaimedCopy the code

Reference counting is the most rudimentary garbage collection algorithm. If an object has no other objects pointing to it, it can be collected. But it doesn’t handle circular references.

Limits on circular references

Function f(){let o1 = {} let o2 = {} o1.a = o2 O2. a = o1 return 100} f()Copy the code

We execute the f function, and it returns a number, which has nothing to do with the internal O1 and O2, but for reference counting, o1 and O2 still refer to each other, so they’re not recycled. This creates a memory leak.

Mark clearance

This algorithm simplifies “whether an object is no longer needed” to “whether an object is available.”

Since 2012, all modern browsers have used the mark-clean garbage collection algorithm. The tag removal method assumes that there is a root object (equivalent to js global object), the garbage collector will periodically start from the root object, all can scan from the root will be retained, the scan will not be collected.

Start scanning from the root object

The part on the right is unreachable, it will be recycled

It’s like a bucket of water that we throw down from the root object, and wherever the water goes, it’s fine, and anything that doesn’t get wet is recycled.

Internal processes

  1. The garbage collector finds all the roots and “marks” (remembers) them.
  2. It then iterates over and “marks” all references from them.
  3. It then iterates over the tagged objects and marks their references. All objects that have been traversed are remembered to prevent future traversal of the same object.
  4. … Do so until all reachable (from the root) references are accessed.
  5. Objects that are not marked are deleted.

Several common memory leaks

  1. The global variable

It can be difficult to tell when global variables need to be automatically freed, so try to avoid using global variables in your development to increase effective memory utilization.

  1. The event binding is not removed

Although the DOM element is removed, the event bound to the element is still there. If the event binding is not removed in time, memory leaks are likely to occur in IE9 and later versions. Modern browsers don’t have this problem, so just take a look.

let div = document.querySelector(".div"); let name = 'lee' let handler = function () { console.log(name); } div. AddEventListener (" click ", handler, false) div. ParentNode. RemoveChild (div) / / under Internet explorer 9 is still in the old versionCopy the code
  1. Invalid DOM reference

Sometimes it’s useful to store the DOM as the key to an object, but remember to dereferent it when you don’t need it.

var ele = { node: document.getElementById('node') }; document.body.removeChild(document.getElementById('node')); // There is still a reference to node in eleCopy the code
  1. SetInterval timer/setTimeout

Once we remove the node elsewhere, the callback of the timer becomes meaningless. However, it continues to execute, causing the callback to fail to be collected, and thus causing the internal resData to fail to be collected. So we should clear the timer in time.

let resData = 100
let callback = function () {
    let node = document.querySelecter('.p')
    node && (node.innerHTML = resData)
}

setInterval (callback, 1000)
Copy the code

In addition, closures have nothing to do with memory leaks. They are only due to the garbage collection mechanism of the versions before IE9, which causes memory to be unable to be collected. This is an IE problem, and most modern browsers do not have this problem. Of course closures can cause memory leaks if used improperly.

WeakMap, WeakSet

Es6 WeakMap is similar to Map in that it is used to generate a set of key and value pairs. The difference is that WeakMap is a weak reference, and the object pointed to by its key name is not included in the garbage collection mechanism. In addition, WeakMap only accepts objects as key names (except null), while Map can accept various types of data as keys.

WeakMap is a structure that helps prevent memory leaks. Once references to keys are eliminated, the memory it uses is freed by garbage collection. The key value pair saved by WeakMap will also disappear automatically. The same is true for weaksets, which are stored internally as weak reference objects and will not be included in garbage collection.

Take an example from ruan Yifeng’s ES6 documentation:

let myWeakmap = new WeakMap();

myWeakmap.set(
  document.getElementById('logo'),
  {timesClicked: 0})
;

document.getElementById('logo').addEventListener('click', function() {
  let logoData = myWeakmap.get(document.getElementById('logo'));
  logoData.timesClicked++;
}, false);

Copy the code

In the above code, we use the DOM object as the key name, and each time we click, we update the state. We put this state as the key value in the WeakMap. Once the DOM node is removed, the state automatically disappears, with no memory leak risk.

WeakSet is similar to WeakMap. There are two differences between WeakSet structure and SET structure:

  1. Objects in a WeakSet are weak references and will not be counted in garbage collection
  2. Members can only be objects and cannot be values of any other type

So from the perspective of garbage collection, the rational use of WeakMap and WeakSet can help us avoid memory leaks.

summary

There is no human intervention in the JS garbage collection mechanism, the browser will regularly inspect, the JS engine has done a lot of internal optimization, so that it can perform faster, modern browsers are basically using a clearly marked method for garbage collection. Understand the cause of memory leak and how to avoid, prevent rollovers accident 🐵

Resources: developer.mozilla.org, javascript.info