Common memory leak scenarios
Memory leak Memory Leak
It refers to the heap memory that has been dynamically allocated in the program. Due to negligence or error, the program is not released or cannot be released , Cause the waste of system memory , Causes the procedure to run the speed to slow down even the system crashes and so on the serious consequence . Memory leaks are not physical disappearances , But after the application allocates some memory , Because of a design mistake , As a result, the control of this segment of memory is lost before releasing it , This results in a waste of memory . For memory leak detection ,Chrome
Provides performance analysis tools Performance
, Can be more convenient to view the occupation of memory and so on .
Memory recovery mechanism
image C
Language such as the underlying language generally has the underlying memory management interface , for example malloc()
and free()
etc. , about JavaScript
When a variable is created, it automatically allocates memory , And automatically release them when they're not in use . stay Js
Reference types of the seven basic types Object
Variable, which occupies a large memory space and the size is not fixed , The object is actually stored in heap memory , Storing pointers to objects in stack memory , Access to objects is by reference . Variables executed in the stack area are accessed by values , When its scope is destroyed, the variable is destroyed , And heap variables that use reference access , After a scope disappears, there may still be references in the outer scope or other scopes , It can't be destroyed directly , At this point, we need to calculate whether the heap variable belongs to the variable that is no longer needed by the algorithm , To determine whether memory recycling is needed , stay Js
There are two kinds of garbage collection algorithms: reference counting and mark clearing .
Reference counting algorithm
For the reference count garbage collection algorithm , Whether an object no longer needs to be simplified is defined as whether the object has other variables or objects referring to it , If there is no reference to the object , The object will be recycled by the garbage collection mechanism . ad locum , The concept of an object does not refer specifically to JavaScript
object , It also includes function scope or global lexical scope . Reference count garbage collection algorithm is less used , Mainly in the IE6
And IE7
Wait for the lower version IE
The browser uses .
var obj = {
a : {
b: 11
}
}
// At this point, two objects are created , One as the other a Properties are referred to as objects 1, The other was obj Variable references are called objects 2
// In this case, both objects have referenced variables , Can't reclaim memory
var obj2 = obj;
// At this time, for obj Referenced objects 2, There has been a obj And Obj2 References to two variables
obj = null;
// take obj For the object 2 The reference of , At this point the object 2 There is still obj2 A quote
var a2 = obj2.a;
// Reference object 1, At this point the object 1 Yes a And a2 Two quotes
obj2 = null;
// Release object 2 A reference to , At this point the object 2 The number of citations for is 0, It can be recycled by garbage
// object 2 Of a Attribute references are released , At this point the object 1 Only a2 A quote
a2 = null;
// relieve a2 For the object 1 References to , At this point the object 1 It can be recycled by garbage
But there is a limitation to the reference count garbage collection algorithm , When an object is referred to repeatedly , Will cause memory leaks , In other words, the reference count garbage collection algorithm cannot handle objects that are referred to in a circular way .
function funct() {
var obj = {}; // Name it object 1, In this case, the number of references is 1
var obj2 = {}; // Name it object 2, In this case, the number of references is 1
obj.a = obj2; // obj Of a Property reference obj2, At this point the object 2 The number of citations for is 2
obj2.a = obj; // obj2 Of a Property reference obj, At this point the object 1 The number of citations for is 2
return 1;
// At this point, the stack is executed obj Variables and obj2 Variables are destroyed , object 1 With the object 2 Reduce the number of citations of 1
// object 1 The number of citations for is 1, object 2 The number of citations for is 1, Neither object will be garbage collected by the reference counting algorithm
}
funct();
// Two objects are created , And quote each other , It forms a cycle , They leave the function scope when called , So they're no longer needed , Can be recycled , However, they all reference each other at least once , So they won't be recycled .
Tag clearing algorithm
For the reference count garbage collection algorithm , Whether the object no longer needs simplification is defined as whether the object can be obtained , The algorithm sets up a root root
The object of , stay Javascript
Reagan is the global object , The garbage collector will periodically start at the root , Find all objects referenced from the root , Then look for the objects that these objects refer to , So keep looking down . Start at the root , The garbage collector will find all available objects and collect all unavailable objects , This solves the problem of circular references . All modern browsers use mark clean garbage collection algorithms , All right JavaScript
The improvement of garbage collection algorithm is based on the improvement of mark clearing algorithm .
- When the garbage collector runs, it marks all variables stored in memory .
- then , It will remove the variables in the runtime environment and the variables referenced by the variables in the environment .
- thereafter , Variables that are still marked are considered variables ready to be deleted , The reason is that these variables are no longer accessible in the runtime environment .
- Last , The garbage collector completes the memory cleanup , Destroy the tagged values and reclaim the memory space they occupy .
Common memory leak scenarios
Unexpected global variables
stay JavaScript
There is no strict definition of how to handle undeclared variables in , Global variables can be defined even in the scope of local functions , This unexpected global variable can store a lot of data , And because it can pass through global objects such as window
Access to , Therefore, memory recycling does not consider it to be the memory that needs to be recycled, but always exists , It can only be released when the window is closed or the page is refreshed , Causing an unexpected memory leak , stay JavaScript
In strict mode, this unexpected way of defining global variables throws an exception , You can also use eslint
Perform a pre check of this state . In fact, it's not a good habit to define global variables , If you have to use global variables to store large amounts of data , Make sure you set it to zero when you're done null
Or redefine it , One of the main causes of increased memory consumption associated with global variables is caching , Caching data is for reuse , The cache must have a size cap to be useful , High memory consumption causes the cache to breach the upper limit , Because the cached content cannot be recycled .
function funct(){
name = "name";
}
funct();
console.log(window.name); // name
delete window.name; // If you do not delete it manually, it will always exist without closing or refreshing the window
Forgotten timer
timer setInterval
It must be cleaned up in time , Otherwise, it may not be recycled because the variables or functions referenced in it are considered necessary , If internally referenced variables store a lot of data , May cause the page to occupy too much memory , This causes an unexpected memory leak .
<template>
<div></div>
</template>
<script>
export default {
creates: function() {
this.refreshInterval = setInterval(() => this.refresh(), 2000);
},
beforeDestroy: function() {
clearInterval(this.refreshInterval);
},
methods: {
refresh: function() {
// do something
},
},
}
</script>
Out of the DOM References to
Sometimes save DOM
The data structure inside the node is very useful , For example, you need to quickly update a few lines of the table , Put each line DOM
It makes sense to save it as a dictionary or an array . At the same time DOM
The element has two references : In a DOM
In the tree , The other one is in the dictionary . In the future, if you decide to delete these lines , You need to clear both references . Besides, consider DOM
Reference problems within the tree or child nodes , If your JavaScript
A table is saved in the code <td>
References to , When you decide to delete the entire table in the future , Intuition holds that GC
It will recycle everything except what was saved <td>
Other nodes than , This is not the case , this <td>
Are child nodes of the table , Child elements are referenced to parent elements , Because the code is preserved <td>
References to , Causes the entire table to remain in memory , So it's saving DOM
When the element is referenced , Be careful .
var elements = {
button: document.getElementById("button"),
image: document.getElementById("image"),
text: document.getElementById("text")
};
function doStuff() {
elements.image.src = "https://www.example.com/1.jpg";
elements.button.click();
console.log(elements.text.innerHTML);
// More logic
}
function removeButton() {
// Button is body The offspring element of
document.body.removeChild(elements.button);
elements.button = null; // Clear the reference to this object
}
Closure
Closure is JavaScript
A key aspect of development , Closures allow you to access external function scopes from internal functions , In a nutshell, it can be said that a function scope can be accessed from another function scope instead of having to implement a scope chain structure in the function scope . Because a closure carries the scope of the function that contains it , So it takes up more memory than other functions , Overuse of closures can lead to excessive memory consumption , The closure that is no longer needed needs to be cleared manually after use .
function debounce(wait, funct, ...args){ // Anti shake function
var timer = null;
return () => {
clearTimeout(timer);
timer = setTimeout(() => funct(...args), wait);
}
}
window.onscroll = debounce(300, (a) => console.log(a), 1);
The forgotten listener pattern
When the listener mode is implemented and the related event handling function is mounted in the component , When the component is destroyed and it is not cleared actively , The variables or functions that are referenced are considered necessary and will not be recycled , If internally referenced variables store a lot of data , May cause the page to occupy too much memory , This causes an unexpected memory leak .
<template>
<div ></div>
</template>
<script>
export default {
created: function() {
global.eventBus.on("test", this.doSomething);
},
beforeDestroy: function(){
global.eventBus.off("test", this.doSomething);
},
methods: {
doSomething: function() {
// do something
},
},
}
</script>
Forgotten event listeners
When the event listener mounts the relevant event handler in the component , When the component is destroyed and it is not cleared actively , The variables or functions that are referenced are considered necessary and will not be recycled , If internally referenced variables store a lot of data , May cause the page to occupy too much memory , This causes an unexpected memory leak .
<template>
<div></div>
</template>
<script>
export default {
created: function() {
window.addEventListener("resize", this.doSomething);
},
beforeDestroy: function(){
window.removeEventListener("resize", this.doSomething);
},
methods: {
doSomething: function() {
// do something
},
},
}
</script>
Forgotten Map
When using Map
When storing objects , It's like breaking away from DOM
References to , If you do not actively clear the reference , It also causes memory not to be recycled automatically , In the case of keys as objects , May adopt WeakMap
,WeakMap
Objects are also used to hold key value pairs , It is weakly referenced to a key and must be an object , And the value can be any object or original value , And because it's a weak reference to an object , It doesn't interfere with Js
The garbage collection of .
var elements = new Map();
elements.set("button", document.getElementById("button"));
function doStuff() {
elements.get("button").click();
// More logic
}
function removeButton() {
// Button is body The offspring element of
document.body.removeChild(elements.get("button"));
elements.delete("button"); // Clear the reference to this object
}
Forgotten Set
When using Set
When storing objects , It's like breaking away from DOM
References to , If you do not actively clear the reference , It also causes memory not to be recycled automatically , If needed Set
Reference object , May adopt WeakSet
,WeakSet
Object allows you to store unique values for weak references to objects ,WeakSet
The values in the object are also not repeated , And only weak references to objects can be saved , And because it's a weak reference to an object , It doesn't interfere with Js
The garbage collection of .
var elements = new Set();
var btn = document.getElementById("button");
elements.add(btn);
function doStuff() {
btn.click();
// More logic
}
function removeButton() {
document.body.removeChild(btn); // Button is body The offspring element of
elements.delete(btn); // eliminate Set Reference to this object in
btn = null; // Clear references
}
A daily topic
https://github.com/WindrunnerMax/EveryDay
Reference resources
https://zhuanlan.zhihu.com/p/60538328
https://juejin.im/post/6844903928060985358
https://jinlong.github.io/2016/05/01/4-Types-of-Memory-Leaks-in-JavaScript-and-How-to-Get-Rid-Of-Them/