Abstract: it is well known that the application is running in the process of take up some memory space, and after the operation will have to release the memory no longer used, can appear otherwise continue to rise, memory in the below image will affect the speed of the program running on one hand, on the other hand, serious word will lead to the collapse of the entire program.

It is well known that the application is running in the process of take up some memory space, and after the operation will have to release the memory no longer used, can appear otherwise continue to rise, memory in the below image will affect the speed of the program running on one hand, on the other hand, serious word will lead to the collapse of the entire program.

Memory management in JavaScript

– Memory: consists of read/write units, representing a piece of operable space. – Management: manually operate the application, use and release of a space; – Memory management: developers actively apply for space, use space, release space; – Management process: Apply – Use – Release

Some languages (such as’ C ‘) need to manually free memory, but this can be cumbersome, so many languages, such as’ JAVA ‘, provide an automatic memory management mechanism called ‘garbage collection’. Garbage Collecation, or GC, is also available in the JavaScript language.

Stop The World

Before introducing the garbage collection algorithm, let’s take a look at “** full pause **”. Garbage collection algorithms need to suspend The application logic before execution, and then execute The application logic after garbage collection. This behavior is called “Stop The World” (‘ Stop The World ‘). For example, if a GC takes 50ms, the application logic pauses for 50ms.

The purpose of the total pause is to resolve inconsistencies between the application logic and what the garbage collector sees.

Take, for example, eating at a cafeteria and coming back happily from your food only to find that the waiter has taken away your cutlery. Here, the server is the garbage collector, the cutlery is the distribution object, and we are the application logic. From our point of view, the cutlery is temporarily placed on the table, but the waiter seems to think you don’t need it anymore, so they take it away. You and the waiter do not see the same thing, which leads to the waiter doing something we do not expect. Therefore, to prevent the application logic from being inconsistent with what the garbage collector sees, the garbage collection algorithm needs to stop the application logic during execution.

Garbage collection in ‘JavaScript’

Examples of situations that would be considered garbage in JavaScript are as follows:

– The object is no longer referenced; – Objects cannot be asked from the root;

The common GC algorithms are as follows:

The most common garbage collection method used by early browsers is called “reference counting”. The language engine has a “reference table” that holds the number of references to all resources (usually values) in memory. If the number of references to a value is zero, the value is no longer needed, so it can be freed.

const user1 = {age: 11}
const user2 = {age: 22}
const user3 = {age: 33}

const userList = [user1.age, user2.age, user3.age]
Copy the code

User1, user2, and user3 are referenced by the userList, so their reference count is not zero and will not be recycled

function fn() {
    const num1 = 1
    const num2 = 2
}

fn()
Copy the code

After the fn function is executed, num1 and num2 are local variables. After the fn function is executed, their reference count will be zero and all such code will be recycled as “garbage”.

Reference counting algorithms have one big problem: circular references

function objGroup(obj1, obj2) {
    obj1.next = obj2
    obj2.prev = obj1

    return {
        o1: obj1,
        o2: obj2,
    }
}

let obj = objGroup({name: 'obj1'}, {name: 'obj2'})
console.log(obj)
Copy the code

In the example above, obj1 and obj2 refer to each other through their respective attributes, and none of them have a zero reference count so that they are not collected by the garbage collection mechanism, resulting in a waste of memory.

In fact, reference counting algorithm has a relatively big disadvantage, is that we need to set aside a separate space to maintain the reference count of each variable, which for large programs, space overhead is relatively large.

The advantages of the reference counting algorithm are as follows: – When the reference count is zero, garbage is immediately collected. – Minimize program pauses;

Disadvantages of reference counting algorithm: – Unable to recycle the object referenced by loop; – Large space overhead;

The core idea of Mark-sweep: Mark and Sweep are completed in two stages. 1. Traverse all objects to find marked active objects; 2. Traverse all objects to remove unmarked objects; 3. Reclaim space.

The advantages of the tag clearing algorithm are as follows: Compared with the reference counting algorithm, the biggest advantage of the tag clearing algorithm is that it can recycle the referenced objects, and it is also the algorithm most used by V8 engine. The disadvantages of the tag clearing algorithm are:

In the figure above, we can see that the red area is a root object, which is a global variable, and will be marked; Blue areas are unmarked objects that are collected by the collection mechanism. There is a problem. On the surface, the blue area has reclaimed three Spaces, but these three Spaces are discontinuous. When we have an object that needs three Spaces, the space we just reclaimed cannot be allocated, which is called “space fragmentation”.

In order to solve the problem of memory fragmentation and improve the utilization of memory, mark-compact algorithm is introduced.

Tag cleanup can be seen as an enhancement to tag cleanup. The operation of the tag phase is the same as that of tag clearing.

The cleanup phase performs a cleanup, moving object locations, moving surviving objects to one side, and then cleaning up memory outside end boundaries.

The disadvantage of tag collation is that objects are not immediately recycled when they are moved. Incremental Marking ‘V8’ has been optimized to reduce the total pause time by dividing the Marking process into small steps for a single pause. After each small step, let the application logic run for a few moments, and do this multiple times before completing the mark.

Prolonged ‘GC’, which leads to application pauses and unresponsiveness, will result in a poor user experience. Starting in 2011, v8 replaced the “total pause” flag with an incremental one. The improved marking method reduces the maximum pause time to 1/6 of the original.

V8 engine garbage collection strategy

– Adopt the idea of generational recycling; – Memory is divided into new generation, old generation;

Different algorithms are used for different objects: (1) New generation: the survival time of objects is short. Newborn objects or objects that have been garbage collected only once. (2) Old generation: the object lives for a long time. Objects that have undergone one or more garbage collections.

The space of the V8 heap is equal to the space of the new generation plus the space of the old generation. And for different operating systems to do the space of the memory limit.

This is more than enough memory for a browser. Reasons for limiting memory:

According to the GC mechanism of the browser, after continuous testing, if the memory is set a little larger, the time of ‘GC’ recovery will reach the user’s perception, which will cause perceptual lag.

Reclaiming new generation objects

The recycling of new generation objects is based on the insane replication algorithm ** (‘ Scavenge algorithm ‘). The Cheney algorithm is used to implement the Scavenge algorithm.

The ‘Cheney algorithm’ divides the memory into two equally large Spaces, ‘From’ for use and ‘To’ for free.

Check the surviving objects in the ‘From’ space. If the object is alive, check whether it meets the promotion conditions. If it meets the conditions, it will be promoted To the old generation, otherwise it will be copied From the ‘From’ space To ‘space. If the object is not viable, the space of the nonviable object is freed. After the replication is complete, the roles of ‘From’ space and ‘To’ space are reversed.

Object promotion mechanism

A new generation of ‘GC’ that is still alive needs promotion. When an object is copied From the ‘From’ space To the ‘To’ space, if the ‘To’ space usage exceeds 25%, the object is promoted directly To the old generation. The reason for this 25% is To recycle the To space into the From space when the object memory is allocated. If the proportion is too large, subsequent memory allocation will be affected.

Reclaim old generation objects

The old generation objects are mainly recycled by mark clearing, mark collation, incremental mark algorithm, mainly by mark clearing algorithm, only in the case of insufficient memory allocation, the ** mark collation algorithm.

1. First, the garbage space is recovered using the mark clearance; 2. Spatial optimization was carried out by label finishing; 3. Incremental marking is used for efficiency optimization; Comparison between Cenozoic generation and old generation Recycling Cenozoic generation uses space for time mechanism because it occupies less space. Old generation area space is relatively large, not suitable for a large number of copy algorithm and mark sorting, so the most commonly used is ** mark clearing ** algorithm, in order to minimize the total pause time.

Memory leak identification method

Let’s start with some memory-consuming code:

<button class=" BTN "> Click </button> <script> const BTN = document.querySelector('.btn') const arrList = [] btn.onclick = function() { for(let i = 0; i < 100000; I++) {const p = document. The createElement method (' p ') / / p.i nnerHTML = 'I am a p element' document. The body. The appendChild (p)} arrList. Push (new Array(1000000).join('x')) } </script>Copy the code

Use browser ‘Performance’ to monitor memory changes

Click Record, and then we will perform the operation that we feel consumes the performance, after the operation is finished, click ‘stop’ to stop recording.

And then we look at what’s causing the memory leak, and we just focus on memory.

You can see that there is a little groove in the memory where the short time consumption is faster, and the drop is that the browser is doing garbage collection.

Performance optimization

1. Avoid global variables

– Global variables will be mounted under window; – Global variables have at least one reference count; – Global variables live longer and continue to consume memory; – Use local variables as far as possible in the case of clear data scope; 2. Reduce the level of judgment

Function doSomething(part, chapter) {const parts = ['ES2016', 'Vue', 'React', 'Node'] if (part) {if (parts.includes(part)) {console.log(' chapter > 5 ') {console.log(' you need to provide VIP status ')}} } else {console.log(' please confirm module info ')}} doSomething('Vue', 6) Chapter) {const parts = ['ES2016', 'Vue', 'React', 'Node'] if (! Part) {console.log(' Please confirm module information ') return} if (! Parts.includes (part)) return console.log(' includes ') if (chapter > 5) {console.log(' includes ')}} doSomething('Vue', 6)Copy the code

3. Reduce the number of data reads. For frequently used data, cache the data.

<div id="skip" class="skip"></div>

<script>
    var oBox = document.getElementById('skip')

    // function hasEle (ele, cls) {
    //     return ele.className === cls
    // }

    function hasEle (ele, cls) {
        const className = ele.className
        return className === cls
    }

    console.log(hasEle(oBox, 'skip'))
</script>
Copy the code

4. Reduce activity in the circulatory body

Var test = () => {var I var arr = ['Hello World ', 25, 'Hello World '] for(I = 0; i < arr.length; I ++) {console.log(arr[I])}} var test = () => {var I var arr = ['Hello World! [(I = 0; I = 0; I = 0; i < len; i++) { console.log(arr[i]) } }Copy the code

5. Event binding optimization

<ul class="ul"> <li>Hello World! </li> <li>25</li> <li> Robe with child < / li > < / ul > < script > var list = document. QuerySelectorAll (' li ') function showTxt (ev) { Console. log(ev.target.innerhtml)} for (item of list) {item.onclick = showTxt} function showTxt(ev) {var target = ev.target if (target.nodeName.toLowerCase() === 'li') { console.log(ev.target.innerHTML) } } var ul = document.querySelector('.ul') ul.addEventListener('click', showTxt) </script>Copy the code

6. Avoid closure traps

<button class=" BTN "> click </button> <script> function foo() {let el = document.querySelector('.btn') el.onclick = Function () {console.log(el.classname)}} foo() function foo1() {let el = document.querySelector('.btn') El.onclick = function() {console.log(el.classname)} el = null // Set el to null to prevent references in closures from being recycled} foo1() </script>Copy the code

This article is shared from Huawei cloud community “Vue Advanced (Yao Lujiu) : JS garbage recycling mechanism”, the author of the original: SHQ5785.

Click to follow, the first time to learn about Huawei cloud fresh technology ~