一、内存生命周期
- 内存分配:当我们申明变量、函数、对象的时候,系统会自动为他们分配内存
- 内存使用:即读写内存,也就是使用变量、函数等
- 内存回收:使用完毕,由垃圾回收机制自动回收不再使用的内存
二、内存泄漏
内存泄漏:不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
三、检测内容泄漏的方法
1.通过谷歌浏览器检测:
打开chrome检查,点击Performance,勾选Memory,点击左上角的Record小圆点,开始录制
录制时进行一些用户基本操作,操作结束后点击stop按钮,结束录制,页面会呈现录制结果
结果:
判定当前是否有内存泄漏
- 多次快照后,比较每次快照中内存的占用情况,如果呈上升趋势,那么可以认为存在内存泄漏
- 某次快照后,看当前内存占用的趋势图,如果走势不平稳,呈上升趋势,那么可以认为存在内存泄漏
- 经过一些反复测试后,你看到的是锯齿状的图形(有上有下),说明你的程序中有很多短时存在的对象。
只看JS Heap(堆内存)这条线:
2.通过node.js的process. memoryUsage()检测
console.log(process.memoryUsage());
// {
// rss: 27709440,
// heapTotal: 5685248,
// heapUsed: 3449392,
// external: 8772
// }
- rss(resident set size):所有内存占用,包括指令区和堆栈。
- heapTotal:"堆"占用的内存,包括用到的和没用到的。
- heapUsed:用到的堆的部分。
- external: V8 引擎内部的 C++ 对象占用的内存。
四、可能导致内存泄漏的案例
1.声明时内存泄漏
function fn() {
a = 1;
}
fn();
console.log(a); // 1
解决:声明时使用var、let、const.
function fn() {
let a = 1;
}
fn();
console.log(a); // a is not defined
2.this导致内存泄漏
function fn() {
this.a = 1; // this指向全局对象window,导致内存泄漏
}
fn();
console.log(this.a); // 1
3.没清除setInterval导致内存泄漏
setInterval没有清除,仅仅清除dom元素,定时器依旧不断工作
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div>
<p id="text"></p>
<button id="btn">移除</button>
</div>
<script>
window.onload = function() {
let p = document.getElementById('text');
setInterval(function() {
let time = new Date();
p.innerHTML = JSON.stringify(time);
console.log(111);
}, 1000);
let btn = document.getElementById('btn');
btn.onclick = function() {
p.remove();
}
}
</script>
</body>
</html>
解决:删除定时器
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div>
<p id="text"></p>
<button id="btn">移除</button>
</div>
<script>
window.onload = function() {
let timer = null;
let p = document.getElementById('text');
timer = setInterval(function() {
let time = new Date();
p.innerHTML = JSON.stringify(time);
console.log(111);
}, 1000);
let btn = document.getElementById('btn');
btn.onclick = function() {
p.remove();
clearInterval(timer);
}
}
</script>
</body>
</html>
4.闭包导致内存泄漏
function Person() {
this.name = 'John';
this.age = 12;
}
Person.prototype.showName = function() {
let _this = this; //this常驻于内存中,闭包里的变量会持续保存,没有清理就会一直占用内存
return function() {
return _this.name;
}
}
解决方法:保存this的属性,用完要置空。
function Person() {
this.name = 'John';
this.age = 12;
}
Person.prototype.showName = function() {
let name= this.name; //this常驻于内存中,闭包里的变量会持续保存,没有清理就会一直占用内存
return function() {
return name;
}
name = null;
}