• preface
  • 1 introduction
  • 2 Main cause of memory leakage
  • 3 Common memory leaks
    • 3.1 Global Variables
    • 3.2 the timer
    • 3.3 Multiple References
    • 3.4 the closure
  • 4 Chrome memory analysis tool
  • data

preface

Before reading this blog, you might want to have some knowledge of JavaScript memory management:

  • Memory management and garbage collection for JavaScript in V8

1 introduction

Memory Leaks: Memory that is no longer needed by an application and is for some reason not returned to the operating system or the Pool of Free Memory.

Possible problems with memory leaks: slowdowns, stuttering, high latency.

2 Main cause of memory leakage

The main cause of JavaScript memory leaks is a few Unwanted References.

Unwanted References refer to the memory that the developer no longer needs, but that for some reason is still marked and left in the active root tree. Unwanted References are the References for the memory. In the context of JavaScript, Unwanted References are variables that you no longer need that point to some memory that could have been released.

3 Common memory leaks

3.1 Global Variables

First, we need to know that global variables in JavaScript are referenced by the root node, so they are not garbage collected throughout the life of the application.

Scenario 1: In JavaScript, referring to an undeclared variable will result in the creation of a new variable in the global environment.

function foo(arg) {
    bar = "this is a hidden global variable";
}
Copy the code

The code above is actually as follows:

function foo(arg) {
    window.bar = "this is an explicit global variable";
}
Copy the code

Suppose that we wanted the bar variable to be used only inside the scope of foo, but this would accidentally create bar in the global scope, which would cause a memory leak.

Scene 2:

function foo() {
    this.variable = "potential accidental global";
}
foo();
Copy the code

Similarly, if we wanted the bar variable to be used only inside the scope of foo, we would be leaking memory if we didn’t know that this inside foo pointed to a global object.

Advice:

  1. Avoid accidentally creating global variables. For example, we could use strict mode, and the first code in this section would report an error without creating a global variable.

  2. Reduce the creation of global variables.

  3. If you must use global variables to store large amounts of data, be sure to null or reallocate the data after processing it.

3.2 the timer

Scenario Example:

for (var i = 0; i < 100000; i++) {
    var buggyObject = {
        callAgain: function () {
            var ref = this;
            var val = setTimeout(function () {
 ref.callAgain();  }, 10);  }  }  buggyObject.callAgain();  buggyObject = null; } Copy the code

3.3 Multiple References

Multiple References: When Multiple objects reference the same object, if one of the references is not cleared, the referenced object cannot be GC.

Scene 1:

var elements = {
    button: document.getElementById('button'),
    image: document.getElementById('image'),
    text: document.getElementById('text')
};
 function doStuff() {  image.src = 'http://some.url/image';  button.click();  console.log(text.innerHTML);  // Much more logic }  function removeButton() {  // The button is a direct child of body.  document.body.removeChild(document.getElementById('button'));   // At this point, we still have a reference to #button in the global  // elements dictionary. In other words, the button element is still in  // memory and cannot be collected by the GC.s } Copy the code

In this case, we keep two references to #button: one in the DOM tree and one in the Elements object. If you decide to reclaim #button in the future, you need to make both references inaccessible. In the above code, since we only cleared references from the DOM tree, the #button is still in memory and not GC.

Scenario 2: If we want to reclaim a table, but we keep a reference to a cell in the table, the entire table will be stored in memory and cannot be GC.

3.4 the closure

Closure: A Closure is a function that can access variables defined in its Enclosing Scope, even if the Enclosing Scope is over. Therefore, closures have the ability to remember the Context around them.

Scenario Example:

var newElem;
function outer() {
   var someText = new Array(1000000);
   var elem = newElem;
   function inner() {
 if (elem) return someText;  }  return function () {}; } setInterval(function () {  newElem = outer(); }, 5); Copy the code

In this example, there are two closures: one is inner, and the other is the anonymous function function () {}. The inner closure refers to someText and elem, and inner is never called. However, we need to note that closures with the same parent scope can share the context. That is, in this example, inner’s someText and elem will be shared with the anonymous function function () {}. However, this anonymous function is then returned by return and assigned to newElem. As long as newElem references the anonymous function, then someText and ELEm are not GC.

Also, notice that var elem = newElem is executed inside outer; , and this newElem refers to the anonymous function returned from the last call to Outer. Imagine that the NTH call to outer holds the anonymous function from the NTH call to Outer. This anonymous function holds a reference to elem and, in turn, a reference to the NTH call to… Therefore, this will cause a memory leak.

Solution: change the code for parameter 1 in setInterval to newElem = outer()();

For detailed analysis of this section, see data 1 and 2.

4 Chrome memory analysis tool

Chrome (latest version 86) developer tools have two memory analysis tools:

  1. Performance

  2. Memory


data

  • 4 Types of Memory Leaks in JavaScript and How to Get Rid Of Them
  • Eradicating Memory Leaks In Javascript