JavaScript 内存泄漏
什么是内存泄漏?
程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。
对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃
不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)
所有高级语言都有自己的内存管理系统,而 js 的内存管理也包含在 v8 中。提供自动内存管理,称为”垃圾回收机制”
垃圾回收机制
垃圾回收机制怎么知道,哪些内存不再需要呢?
引用计数:
语言引擎有一张”引用表”,保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是 0,就表示这个值不再用到了,因此可以将这块内存释放
那么,一个值不再需要了,引用数却不为 0,垃圾回收机制无法释放这块内存,从而导致内存泄漏
示例:
1 | // 地址 arr, 地址: 数组值. 此时 数组值的<引用次数>是 1 |
内存泄漏的识别方法
如果连续五次垃圾回收之后,内存占用一次比一次大,就有内存泄漏。这就要求实时查看内存占用
- 打开开发者工具,选择 性能(performance) 面板
- 在顶部的 栏目里面勾选 Memory
- 点击左上角的录制按钮。
- 在页面上进行各种操作,模拟用户的使用情况。
- 一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况。
结果判定:
如果内存占用基本平稳,接近水平,就说明不存在内存泄漏
如果随着你的操作,内存线不断升高,那么就要小心了
Nodejs 查看当前内存process.memoryUsage()
1 | /** |
判断内存泄漏,以 heapUsed 字段为准
WeakMap
在新建引用的时候就声明,哪些引用必须手动清除,哪些引用可以忽略不计,当其他引用消失以后,垃圾回收机制就可以释放内存。
可以用 WeakSet
和 WeakMap
实现,它们对于值的引用都是不计入垃圾回收机制的,所以名字里面才会有一个”Weak”,表示这是弱引用
如何使用 WeakMap:
1 | const wm = new WeakMap(); |
WeakMap 显示内存示例:
1 | # 首先,打开 Node 命令行。--expose-gc参数表示允许手动执行垃圾回收机制 |
上面代码中,只要外部的引用消失,WeakMap
内部的引用,就会自动被垃圾回收清除。
如果你要往对象上添加数据,又不想干扰垃圾回收机制,就可以使用 WeakMap
也就是 WeakMap
和 WeakSet
对 引用值有关联性
而且 WeakSet 的 value 值,WeakMap 的 key, 只能是对象
JavaScript 内存泄漏