Introduction to the

In C language, we need to manually allocate and release the memory of the object, but in Java, all the memory management is handed over to the Java virtual machine, programmers do not need to manually allocate and release the process of memory, greatly reducing the difficulty of program writing.

Similarly, in javascript, memory management is automatic, and while there are automatic memory management measures, that doesn’t mean programmers don’t have to worry about memory management.

This article takes a closer look at memory management strategies in javascript.

Memory life cycle

The memory life cycle is generally the same for any program.

It can be divided into three steps:

  1. Allocate memory in available space
  2. Use this memory space
  3. At the end of use, the memory space is freed

All programs need to execute the second step manually; for javascript, steps 1 and 3 are implemented implicitly.

Let’s look at an example of allocating memory in javascript.

Allocate memory space by initializing:

var n = 123; // Allocate memory for numbers
var s = 'azerty'; // Allocate memory for String

var o = {
  a: 1.b: null
}; // Allocate memory for objects

// Allocate memory for the array
var a = [1.null.'abra']; 

function f(a) {
  return a + 2;
} // Allocate memory for the function
Copy the code

Allocating memory via function calls:

var d = new Date(a);// Assign a date object with new

var e = document.createElement('div'); // Assign a DOM object

var s = 'azerty';
var s2 = s.substr(0.3); // Since strings in JS are immutable, the substr operation creates a new string

var a = ['ouais ouais'.'nan nan'];
var a2 = ['generation'.'nan nan'];
var a3 = a.concat(a2); 
// Similarly, the concat operation creates a new string
Copy the code

The hardest part about freeing up space is figuring out when it’s no longer being used. In javascript this operation is performed by the GC garbage collector.

The purpose of the garbage collector is to collect objects when they are no longer in use.

Garbage collector in JS

One of the most important criteria for determining whether an object can be reclaimed is references.

If an object is referenced by another object, it cannot be reclaimed.

Reference counting garbage collection algorithm

Reference counting garbage collection algorithm is a relatively simple and concise garbage collection algorithm. He translates whether an object can be reclaimed into whether it can still be referenced by other objects.

If the object is not referenced, then the object is garbage collectable.

Let’s take an example of reference counting:

var x = { 
  a: {
    b: 2}};// We create two objects, the a object and the object created outside of a with curly braces.
// We assign a reference to the object created by the braces to the x variable, so x has a reference to the object created by the braces, which cannot be reclaimed.
// Also, because the a object is created inside the brace object, the brace object has a reference to the a object by default
// Because both objects have references, neither object can be garbage collected

var y = x;  // We assign x to y, and the brace object now has two references

x = 1;   // We assign 1 to x so that only y references objects in braces

var z = y.a;  // Assign a reference to object A in y to z, where object A has two references

y = 'flydean';  // reassign to y, the number of references to the curly brace object is 0, the curly brace object can be reclaimed, but because the inner a object has a z reference
                // So it cannot be recycled for the time being

z = null;       // the z reference is also reassigned, the number of references to the A object is 0, and both objects can be reclaimed
Copy the code

One disadvantage of reference counting is the possibility of circular references.

Consider the following example:

function f() {
  var x = {};
  var y = {};
  x.a = y;        // x references y
  y.a = x;        // y references x

  return 'flydean';
}

f();
Copy the code

In the example above, the A attribute in x references y. The A property in y refers to x.

This leads to a situation of circular references, which eventually leads to a memory leak.

In practice, IE6 and IE7 use garbage collection algorithms for DOM objects with reference counts, so memory leaks can occur.

var div;
window.onload = function() {
  div = document.getElementById('myDivElement');
  div.circularReference = div;
  div.lotsOfData = new Array(10000).join(The '*');
};
Copy the code

In the above example, the myDivElement element in the DOM references itself using circularReference. MyDivElement is not recycled if reference counts are used.

When myDivElement contains a large amount of data, even if it is deleted from the DOM tree, myDivElement will not be garbage collected, resulting in a memory leak.

Mark-and-sweep recovery algorithm

JS garbage collection is similar to Java, which also has reference counting and Mark-and-sweep.

The criterion of this collection algorithm is that the object is unreachable.

In javascript, you scan root objects (global objects in JS), find references to those root objects, and then find references to those referenced objects, layer by layer.

Finally, the garbage collector finds all reachable and unreachable objects.

Using unattainable to mark objects that are no longer in use can effectively solve the problem of circular references in reference counting.

In fact, almost all modern browsers now support the Mark-and-sweep reclamation algorithm.

Debugging memory Problems

If a memory leak is sent, how do we debug and find the problem?

In nodeJS we can add –inspect and use the Chrome Debugger to do this:

node --expose-gc --inspect index.js
Copy the code

The above code will enable nodeJS debugging.

Let’s look at the output:

Debugger listening on ws:/ / 127.0.0.1:9229/88 c23ae3 CD - 9081-41-98 b0 - d0f7ebceab5a
For help, see: https://nodejs.org/en/docs/inspector
Copy the code

The result tells us two things. The first thing is the port on which the Debugger listens. Port 9229 127.0.0.1 will be enabled by default. A unique UUID is assigned for differentiation.

The second thing is to tell us that nodeJS uses Inspector.

To use Chrome devTools for debugging, we have enabled –inspect mode.

Type chrome://inspect:

You can see the Chrome Inspect interface directly in Remote Target if you already have the Inspect NodeJS application enabled locally.

Select the target you want to debug and click inspect to launch the Chrome devTools debugging tool:

You can profile your application and you can debug it.

Memory leaks in Closures

The so-called closure refers to the function within a function. The internal function can access the parameters or variables of the external function, resulting in the reference of the internal variables of the external function.

Let’s look at a simple closure example:

 function parentFunction(paramA)
 {
 var a = paramA;
 function childFunction()
 {
 return a + 2;
 }
 return childFunction();
 }
Copy the code

In the example above, childFunction refers to the variable A of parentFunction. As long as childFunction is in use, a cannot be released, resulting in parentFunction not being garbage collected. In fact, Closure contains a reference to the parent function by default.

Let’s look at the following example:

 <html>
 <body>
 <script type="text/javascript">
 document.write("Program to illustrate memory leak via closure");
 window.onload=function outerFunction(){
 var obj = document.getElementById("element");
 obj.onclick=function innerFunction(){
 alert("Hi! I will leak");
 };
 obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
 // This is used to make the leak significant
 };
 </script>
 <button id="element">Click Me</button>
 </body>
 </html>
Copy the code

In the above example, obj references the DOM object element, whose onclick is an inner function of the outerFunction, resulting in a reference to the outerFunction, which references obj.

This eventually leads to circular references and memory leaks.

How to solve this problem?

An easy way to do this is to assign null to obj after using it and break the loop reference relationship:

 <html>
 <body>
 <script type="text/javascript">
 document.write("Avoiding memory leak via closure by breaking the circular
 reference");
 window.onload=function outerFunction(){
 var obj = document.getElementById("element");
 obj.onclick=function innerFunction()
 {
 alert("Hi! I have avoided the leak");
 // Some logic here
 };
 obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
 obj = null; //This breaks the circular reference
 };
 </script>
 <button id="element">"Click Here"</button>
 </body>
 </html>
Copy the code

Another neat way to do this is not to use closures, but to split them into two separate functions:

 <html>
 <head>
 <script type="text/javascript">
 document.write("Avoid leaks by avoiding closures!");
 window.onload=function()
 {
 var obj = document.getElementById("element");
 obj.onclick = doesNotLeak;
 }
 function doesNotLeak()
 {
 //Your Logic here
 alert("Hi! I have avoided the leak");
 }
 </script>
 </head>
 <body>
 <button id="element">"Click Here"</button>
 </body>
 </html>
Copy the code

Author: Flydean program stuff

Link to this article: www.flydean.com/js-memory-m…

Source: Flydean’s blog

Welcome to pay attention to my public number: “procedures those things” the most popular interpretation, the most profound dry goods, the most concise tutorial, many you do not know the small skills you find!