内存泄漏

什么是内存泄漏?

程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。
不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
常见的内存泄漏的情况

全局变量

1
2
3
4
const fn = () => {
ts = 'test'
}
// 会默认 window.ts = 'test'

忘记清除的计时器或者回调函数

1
2
3
4
5
6
7
const someResource = getData();
setInterval(function() {
let node = document.getElementById('Node');
if(node) {
node.innerHTML = JSON.stringify(someResource));
}
}, 1000);

脱离DOM的引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const elements = {
button: document.getElementById('button'),
image: document.getElementById('image'),
text: document.getElementById('text')
};
const doStuff = () => {
image.src = 'http://some.url/image';
button.click();
console.log(text.innerHTML);
// Much more logic
}
const removeButton = () => {
// The button is a direct child of body.
document.body.removeChild(document.getElementById('button'));
// At this point, we still have a reference to #button in the global
// elements dictionary. In other words, the button element is still in
// memory and cannot be collected by the GC.
}

闭包

JavaScript开发的一个关键方面是闭包:从父作用域捕获变量的匿名函数。 Meteor开发人员发现了一个特定的情况,由于JavaScript运行时的实现细节,可能以一种微妙的方式泄漏内存:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let theThing = null;
const replaceThing = () => {
let originalThing = theThing;
const unused = () => {
if (originalThing)
console.log("hi");
};
theThing = {
longStr: new Array(1000000).join('*'),
someMethod: () => {
console.log(someMessage);
}
};
};
setInterval(replaceThing, 1000);

javascript的内存管理机制

JavaScript是垃圾回收语言之一。 垃圾回收语言通过定期检查哪些先前分配的内存是否“可达”来帮助开发人员管理内存。 换句话说,垃圾回收语言将管理内存的问题从“什么内存仍可用? 到“什么内存仍可达?”。区别是微妙的,但重要的是:虽然只有开发人员知道将来是否需要一块分配的内存,但是不可达的内存可以通过算法确定并标记为返回到操作系统。
垃圾回收语言泄漏的主要原因是不需要的引用。

1
2
const arr = [1,2,3]
console.log('Hi')

虽然我们没有去调用arr,但是[1,2,3]他们占用了内存因此,js会认为他是不需要被回收的,这就产生了内存泄漏,我们可以

1
2
3
4
let arr = [1,2,3]
console.log('Hi')
arr = null
// 可以使arr为null这样就会认为此变量是个垃圾变量,就会回收它。

内存泄漏的识别方法

• Chrome 浏览器查看内存占用,按照以下步骤操作。
1.打开开发者工具,选择 Timeline 面板。
2.在顶部的Capture字段里面勾选 Memory。
3.点击左上角的录制按钮。
4.在页面上进行各种操作,模拟用户的使用情况。
5.一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况。

• 命令行可以使用 Node 提供的process.memoryUsage方法。

1
2
3
4
5
console.log(process.memoryUsage());
// { rss: 27709440,
// heapTotal: 5685248,
// heapUsed: 3449392,
// external: 8772 }

rss(resident set size):所有内存占用,包括指令区和堆栈。
heapTotal:”堆”占用的内存,包括用到的和没用到的。
heapUsed:用到的堆的部分。
external: V8 引擎内部的 C++ 对象占用的内存。

Author: Kari WanG
Link: https://mingz.wang/2020/09/29/内存泄漏/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.