What is a memory leak?

A memory leak is memory that a program no longer needs, but is not released in time!

Memory life cycle:

1. Allocate memory

In JavaScript, the developer only needs to declare variable values, and JavaScript can handle the allocation of memory itself without the developer's intervention. For example:

var a = 123 / / variable
var obj = { // Allocate memory for objects
    a: 1.b: 2
}

var arr = [1.'a', obj] // Allocate memory for the array
Copy the code

2. Use memory

The use of allocated memory in JavaScript mainly refers to memory reads and writes. You can do this by assigning values to variables or object properties

3. Free memory

We all know that in javascript there is no need for developers to manage memory manually, but in Chrome there is a V8 engine that automatically allocates and reclaims memory, which is garbage collection. This does not mean that memory is not a consideration when writing code, as the V8 garbage collection mechanism has certain rules. There are two common approaches to javascript garbage collection:

1. Reference counting algorithm

Internet Explorer uses the reference counting algorithm, which cannot solve the garbage collection problem of circular references and is prone to memory leakage.

So what is a reference counting algorithm? What is the circular reference problem?

Reference counting means that we have a variable and every time it is referenced the GC mechanism increments the variable count by one. When the number of references decreases the count by one. If the count is zero, it will be released in the next garbage collection, for example:

// Reference counting algorithm
var obj = {}  // obj reference count is 0
var a = obj   // obj reference count is 1
var b = obj   // obj reference count is 2
var a = null  // obj reference count is 1
var b = null  // The obj reference count is 0. In the next garbage collection, obj will be collected and the corresponding memory will be freed
Copy the code

The above code demonstrates the reference counting garbage collection mechanism, but the reference counting algorithm does not work if the object has circular references, for example:

var obj1 = {}
var obj2 = {}
obj1.o = obj2    // Obj2 has a reference count of 1
obj2.o = obj1    // Obj1 has a reference count of 1
// This is a circular reference, so the garbage collection mechanism does not free the memory of obj, obj2.
Copy the code

So with reference counting out of the way, let’s take a look at the current garbage collection algorithm used by major browsers, tag scavenging,

2. Mark clearing algorithm

As of 2012, all modern browsers use the tag sweep garbage collection algorithm. All of the improvements to JavaScript garbage collection algorithms are based on improvements to the mark-sweep algorithm, not on improvements to the mark-sweep algorithm itself and its simplified definition of whether an object is no longer needed.

The tag removal algorithm assumes that an object is set up called root, which in JavaScript is window, and that the garbage collector will periodically start at the root, find all the objects referenced from the root, and then continue to find the objects referenced by those objects.

To add the concept of heap and stack:

As we know, in javascript, all but the eight basic types (eight so far) are object types. In JS, object types are reference types, and entities of content are stored in the heap, as I’ve drawn below:

let obj = { name: 'hello' };
let obj1 = { name: 'world' };
// The memory store corresponding to this object is shown in the following figure
Copy the code

// when obj and obj1 are reassigned
obj = null
obj1 = null
// After the reassignment is complete, the corresponding memory structure will look like the figure below
Copy the code

Of objects in the heap memory did not refer to them, but they also occupy the memory, this needs us to destroy them playing the garbage collection, garbage collection mechanism of V8 engine not only destroy if no one quoted in the heap memory space, and also to defragment heap memory, the V8 GC (GC) work as shown in the diagram below:

V8’s GC can be roughly divided into the following steps: First, GC Root marks the space for active and inactive objects. Currently, V8 adopts the accessibility algorithm, which starts from GC Root to traverse all objects. The marks that can be traversed by GC Root are accessible and called active objects and must be kept in memory. The marks that cannot be traversed by GC Root are unreachable and called inactive objects. These unreachable objects will be cleaned up by the GC.

The second step is to reclaim memory occupied by inactive objects. All objects marked as recyclable in memory are cleaned uniformly after all tags are completed.

Step three, do memory defragment. Generally speaking, after frequent object collection, there will be a large number of discontinuous memory space, we call these discontinuous memory space memory fragmentation.


Intergenerational hypothesis

The V8 engine uses two garbage collectors, the Major collector and the Minor collector (Scavenger). You may ask what the generation hypothesis is:

The first is that most objects are “dead”, which means that most objects live in memory for a short time, such as variables declared inside a function or in a block-level scope, which are destroyed when the function or code block finishes executing. So once memory is allocated, objects of this class quickly become inaccessible;

The second is undead objects that live much longer, such as the global Window, DOM, Web API, and so on.

These two recyclers do the following:

  • Main garbage collector -Major GC, which is responsible for old generation garbage collection.
  • Garbage collector -Minor GC (Scavenger) is responsible for garbage collection of the new generation.

This brings up the concept of new generation memory and old generation memory, dividing the heap into two areas

The memory area of the new generation is generally small, but garbage collection is more frequent, while the characteristics of the memory area of the old generation are that objects occupy relatively large space, objects live for a long time, and garbage collection frequency is low.

Incidentally, garbage collection blocks the process.


Common memory leaks

1. As mentioned earlier, some objects are resident in memory and are considered immortal. For example, the Window object is javascript’s top-level object in the browser and it exists throughout the javascript life cycle. There will be a memory leak, which is of course a very low-level error.

function test({
// Missing the declaration, will be automatically mounted to the window object
str = ' ';
for (let i = 0; i < 100000; i++) {
    str += 'xx';  }  return str;
}
// After the test execution, STR should be useless, but it is resident in memory
test();

Copy the code

2. The timer is not recovered

3. Closure abuse

4. DOM correlation


<button class="remove">remove bbb</button>
<div class="box">bbb</div>
<script>
    const box = document.querySelector('.box');
    document.querySelector('.remove').addEventListener('click'.() = > {
        document.body.removeChild(box);
        // The DOM element is removed from the box. The box is not used but does not free memory, resulting in a memory leak
        console.log(box); 
    })
</script>

Copy the code

Author: GZHDEV

Links: juejin. Cn/post / 695908…

Source: Nuggets