程序的运行需要内存, 对于一些需要持续运行很久的程序, 尤其是服务器进程, 如果不及时释放掉不再需要的内存, 就会导致内存堆中的占用持续走高, 最终可能导致程序崩溃.
不再需要使用的内存, 却一直占用着空间, 得不到释放, 这就叫内存泄漏.
在 JS 中, 我们都知道, 基本数据类型是存在栈 (stack) 中, 而引用数据类型是存在堆 (heap) 中. 存在栈中的数据, 会被自动处理掉. 但存在堆中的数据则不然.
JS 引擎有个垃圾回收机制, 可以帮助我们来清除不需要的数据. 关键来了, 我们怎么告诉 JS 引擎这个我不再需要这个数据呢?
答案就是: 切断它的引用, 让它变成一座无法到达的岛屿.
这就是所谓的 "引用计数". 也就是说, 我们对堆中的引用类型数据做一个遍历, 标记它们被引用的次数:
- let a = {
- name:'zhang'
- };
- let b = a;
- let c = {
- name:'zhao'
- };
- c = null;
在上面的这段代码中,{name:'zhang'}这个对象的引用次数为 2, 分别被变量 a 和变量 b 引用.{name:'zhao'}这个对象一开始被变量 c 引用, 引用次数为 1. 后来 c 被重新赋值,{name:'zhao'}这个对象的引用突然被切断, 再也无法被访问到了, 自己变成了一个 "孤岛式数据", 其引用次数变成了零, 被当成了垃圾.
而垃圾的宿命, 就是被 JS 引擎回收.
我们来执行一下上述这段代码, 每点击一次, 就给 obj 存入 1000 个不同对象的引用, 连续点击 10s, 停止 30s. 并把这个过程录制下来.
怎么录? 打开 Chrome 的 performance 即可录制, 看看这 40s 的内存堆 (JS heap) 的走势.
(结果是令人寒心的, 堆内存占用从 15M 左右飙到最高 30M, 且基本没有什么回落, 居高不下)
现在我们把代码改一改, 在末尾增加一句 this.obj = []. 用于清除本次操作产生的 1000 个引用.
按照同样的手法, 点击 10s, 停止 30s, 总共录制 40s. 效果如下:
(可以看到中途最高飙到 24.7M, 但是垃圾回收在第 5s 和第 10s 都介入了一次, 使得内存占用大幅减少)
可以看到垃圾回收还是很有用的, 同时也可以看到, 垃圾回收并不是无时无刻都在进行, 因为垃圾回收这个操作也有性能损耗, 从我实测的结果来看, 它是按照一定的时间间隔进行的.
来源: https://www.cnblogs.com/zhangnan35/p/11268020.html