JavaScript allocates memory when creating variables (objects, strings, etc.) and "automatically" releases memory when they are no longer used. This process of automatically releasing memory is called garbage collection.
Because of the existence of automatic garbage collection mechanism, most Javascript developers feel that they can not care about memory management, which will lead to memory leakage in some cases.
Memory life cycle
The memory allocated in JS environment has the following declaration cycle:
- Memory allocation: when we declare variables, functions and objects, the system will automatically allocate memory for them
- Memory usage: that is, reading and writing memory, that is, using variables, functions, etc
- Memory recycling: after use, the garbage collection mechanism will automatically recycle the memory that is no longer used
JS memory allocation
In order not to bother programmers to allocate memory, JavaScript completes the memory allocation when defining variables.
var n = 123; // Allocate memory to numeric variables var s = "azerty"; // Allocate memory to strings var o = { a: 1, b: null }; // Allocate memory to objects and the values they contain // Allocate memory to arrays and the values they contain (just like objects) var a = [1, null, "abra"]; function f(a){ return a + 2; } // Allocate memory to functions (callable objects) // Function expressions can also assign an object someElement.addEventListener('click', function(){ someElement.style.backgroundColor = 'blue'; }, false);
Some function calls result in the allocation of object memory:
var d = new Date(); // Assign a Date object var e = document.createElement('div'); // Assign a DOM element
Some methods assign new variables or objects:
var s = "azerty"; var s2 = s.substr(0, 3); // s2 is a new string // Because strings are invariants, // JavaScript may decide not to allocate memory, // Only the range of [0-3] is stored. var a = ["ouais ouais", "nan nan"]; var a2 = ["generation", "nan nan"]; var a3 = a.concat(a2); // The new array has four elements, which is the result of a connecting a2
JS memory usage
The process of using values is actually reading and writing to the allocated memory.
Reading and writing may be to write the attribute value of a variable or an object, or even transfer the parameters of a function.
var a = 10; // Allocate memory console.log(a); // Use of memory
JS memory recycling
JS has an automatic garbage collection mechanism. What is the principle of this automatic garbage collection mechanism?
In fact, it is very simple to find out the values that are no longer used, and then release the memory occupied by them.
Most memory management problems are at this stage.
The hardest task here is to find variables that are no longer needed.
Variables that no longer need to be used, that is, variables at the end of the life cycle, are local variables, which only exist during the execution of the function,
When the function ends and there are no other references (closures), the variable will be marked for recycling.
The life cycle of global variables will not end until the browser uninstalls the page, that is, global variables will not be garbage collected.
Because of the existence of automatic garbage collection mechanism, developers can not care about or pay attention to the problems related to memory release, but the release of useless memory exists objectively.
Unfortunately, even without considering the impact of garbage collection on performance, the latest garbage collection algorithms can not intelligently recycle all extreme cases.
1, What is a memory leak
The program needs memory to run. The operating system or runtime must provide memory whenever the program requests it. For the continuously running service process (daemon), the memory that is no longer used must be released in time. Otherwise, the memory occupation will be higher and higher, which will affect the system performance at first, and then cause the process to crash at last.
In essence, memory leakage is a waste of memory caused by the program's failure to release the memory that is no longer used due to negligence or error.
Simply put, a piece of memory space is applied for and not released after use. Its general expression is that the longer the program runs, the more memory is occupied, and finally all memory is exhausted, and the whole system crashes. A piece of memory requested by a program without any pointer to it, then the memory is leaked.
2, Identification method of memory leakage
The rule of thumb is that if the memory usage increases after five consecutive garbage collections, there will be a memory leak.
This requires real-time view of memory usage.
3, How do we check the memory usage in Chrome browser?
- Open the developer tool and select the Performance panel
- Check Memory at the top
- Click the record button in the upper left corner
- Carry out various operations on the page to simulate the use of users
- After a period of time, click the stop button in the dialog box, and the memory usage during this period will be displayed on the panel (as shown below)
There are two ways to determine whether there is a memory leak:
- After multiple snapshots, compare the memory usage in each snapshot. If it shows an upward trend, it can be considered that there is a memory leak
- After a snapshot, look at the trend chart of current memory occupation. If the trend is unstable and upward, it can be considered that there is a memory leak
Use the process provided by Node in the server environment The memoryusage method checks the memory condition
console.log(process.memoryUsage()); // { // rss: 27709440, // heapTotal: 5685248, // heapUsed: 3449392, // external: 8772 // }
process.memoryUsage returns an object that contains the memory usage information of the Node process.
The object contains four fields, in bytes, with the following meanings:
- rss (resident set size): all memory usage, including instruction area and stack.
- heapTotal: the memory occupied by the "heap", including used and unused.
- Heap used: the portion of the heap used.
- external: the memory occupied by C + + objects inside the V8 engine.
Determine the memory leak, and the heapUsed field shall prevail.
Common memory leak cases:
1. Unexpected global variable
function foo() { bar1 = 'some text'; // The undeclared variable is actually a global variable = > window bar1 this.bar2 = 'some text' // Global variable = > window bar2 } foo();
In this example, two global variables bar1 and bar2 are created unexpectedly
2. Forgotten timers and callback functions
In many libraries, if observer mode is used, callback methods will be provided to call some callback functions.
Remember to recycle these callback functions. Take setInterval as an example:
var serverData = loadData(); setInterval(function() { var renderer = document.getElementById('renderer'); if(renderer) { renderer.innerHTML = JSON.stringify(serverData); } }, 5000); // Called every 5 seconds
If the subsequent renderer element is removed, the entire timer actually has no effect.
But if you don't recycle the timer, the whole timer is still valid. Not only can the timer not be recycled by memory,
Dependencies in timer functions cannot be recycled. In this case, the serverData cannot be recycled.
3. Closure
In JS development, we often use closure, an internal function that has the right to access the variables in the external function containing it.
In the following cases, closures can also cause memory leaks:
var theThing = null; var replaceThing = function () { var originalThing = theThing; var unused = function () { if (originalThing) // Reference to 'originalThing' console.log("hi"); }; theThing = { longStr: new Array(1000000).join('*'), someMethod: function () { console.log("message"); } }; }; setInterval(replaceThing, 1000);
In this code, every time replaceThing is called, theThing gets an object containing a huge array and a someMethod for the new closure.
Meanwhile, unused is a closure that references originalThing.
The key to this example is that closures share scopes. Although unused may not be called, someMethod may be called, resulting in failure to recycle its memory.
When this code is executed repeatedly, the memory will continue to grow.
4.DOM reference
Many times, when we operate on Dom, we will save the Dom reference in an array or Map.
var elements = { image: document.getElementById('image') }; function doStuff() { elements.image.src = 'http://example.com/image_name.png'; } function removeImage() { document.body.removeChild(document.getElementById('image')); // At this time, we still have a reference to #Image. The Image element cannot be recycled by memory }
In the above case, even if we remove the image element, there are still references to the image element, and it is still unable to align for memory recycling.
Another point to note is the reference to the leaf node of a Dom tree.
For example, if we reference the td element in a table, once the entire table is deleted in Dom, we intuitively think that memory recycling should recycle other elements except the referenced td.
But in fact, this td element is a child element 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.
4, How to avoid memory leakage
Remember one principle: return what you don't use in time.
- Reduce unnecessary global variables and use strict patterns to avoid accidental creation of global variables.
- After you finish using the data, release the reference in time (variables in closures, dom references, timer clearing).
- Organize your logic and avoid dead cycles that cause browser jams and crashes.