——————— This is the study note ———————

As front-end business demands increase, we use more memory than ever before. But memory is not infinite, and what about variables and objects that we no longer need? Should we manually release them one by one? Not necessarily. Javascript has an automatic garbage collection mechanism that periodically frees memory for variables and objects that we no longer use

Javascript’s garbage collection mechanism

Javascript will look for variables that are no longer in use, and that means the end of the variable’s life cycle. There are two types of variables in Javascript — global and local — and the declaration cycle for all variables continues until the page is unloaded

A local variable is declared in a function, and its declaration cycle begins with the execution of the function and ends with the execution of the function. During this process, local variables are allocated space on the heap or stack to store their values. At the end of the function, the local variables are no longer used, and the space they occupy is freed

But, in the case of a local variable can’t be recycled by the end of the function, that is a local variable is used by the function of external variables, one of which is the case closure, because at the end of the function, the function of external variables still point to a local variable within the function, the local variables are still in use, so it cannot be recycled

function func1 () {
      const obj = {}
}

function func2 () {
      const obj = {}
      return obj
}

const a = func1()
const b = func2()
Copy the code

In this example, func1 allocates a chunk of memory for obj, but as the function finishes, obj’s space is freed; When func2 executes, memory is allocated for obj, but because obj is eventually returned to b, it is still used, so the memory occupied by obj in func2 will not be freed

There are two ways to implement garbage collection

There are two ways to implement garbage collection: token cleanup and reference counting

Mark clearly

Variables are marked “in” when they enter the execution environment and “out” when they leave the execution environment. Variables marked “in” cannot be reclaimed because they are in use, while variables marked “out” can be reclaimed

function func3 () {
      const a = 1
      const b = 2
      // When the function is executed, a and B are marked into the environment respectively
}

func3() // When the function is finished, a and b are marked out of the environment and reclaimed
Copy the code

Reference counting

The number of times a variable of reference type is referenced after it is declared is counted. When the number of times is 0, the variable is reclaimed

function func4 () {
      const c = {} // The reference count of the reference type variable c is 0
      let d = c // c is referenced by D. The reference count of C is 1
      let e = c // c is referenced by e. C has a reference count of 2
      d = {} The reference count of c is reduced to 1
      e = null // e does not reference c any more. If the reference count of C decreases to 0, it will be reclaimed
}
Copy the code

However, the reference counting method has a relatively obvious disadvantage — circular references

function func5 () {
      let f = {}
      let g = {}
      f.prop = g
      g.prop = f
      // Since f and g reference each other, the count can never be 0
}
Copy the code

In this case, you need to manually free the memory of the variable

f.prop = null
g.prop = null
Copy the code

In modern browsers, the way Javascript is used is clearly marked, so we don’t have to worry about circular references

What is a memory leak?

Essentially, a memory leak is memory that is no longer needed and, for some reason, cannot be freed.


Common examples of memory leaks

1) Global variables are mapped as memory leaks

             function fn() {
   		name = "You and ME."
             }
   	     console.log(name)Copy the code



In javascript, we handle undeclared variables. In this example, we define the name in the global object, which in the browser is the window. Global variables in a page are destroyed only when the page is closed. So this is a memory leak, which in this case is a simple string, but in real code, it’s often much worse.

Another case of accidentally creating a global variable.

                function fn() {
   			this.name = "You and ME."
   		}
   		console.log(name)Copy the code



In this case this is referred to the global variable window, accidentally creating the global variable. We talked about global variables defined in unexpected situations, and there are some global variables in the code that we define explicitly. If you use these global variables to temporarily store large amounts of data, remember to re-assign them to null after use.

2) Undestroyed timer and callback function as memory leak

        function fn() {
    		return 2
    	}
    	var oTxt = fn();
   	setInterval(function() {
	    var oHtml = document.getElementById("test")
	    if(oHtml) { oHtml.innerHTML = oTxt; }},1000); // Call once every secondCopy the code

If subsequent oHtml elements are removed, the entire timer has virtually no effect. But if you don’t have a timer, the entire timer still works, not only can the timer not be reclaimed, but also the dependencies in the timer function cannot be reclaimed. In this case fn cannot be recycled.

3) Closure as a memory leak

In JS development, we often use closures, an internal function that has access to variables in the enclosing function. Closures can also cause memory leaks in the following cases.


3) DOM references become memory leaks

A lot of times, when we operate on the Dom, we store references to the Dom in an array or in a Map.

        var elements = {
    		txt: document.getElementById("test")}function fn() {
    		elements.txt.innerHTML = "1111"
    	}
    	function removeTxt() {
    		document.body.removeChild(document.getElementById('test'));
    	}
    	fn();
    	removeTxt()
    	console.log(elements.txt)Copy the code



In the example above, even though we removed the test element, there was still a reference to the test element and it was still unaligned for reclamation. Another point to note is the reference to a leaf node of a Dom tree. For example: if we reference the TD element in a table, once the entire table is removed from the Dom, it is intuitive to assume that memory reclamation should reclaim everything except the referenced TD element. But in fact, the TD element is a child of the entire table and retains a reference to its parent element. This will result in no memory reclamation for the entire table. So we need to be careful with references to Dom elements.