参考:http://www.ruanyifeng.com/blog/2017/04/memory-leak.html
一、内存泄露
程序的运行需要内存。只要程序提出要求,操作系统或者运行时就必须供给内存。
对于持续运行的服务进程,必须及时释放不再用到的内存。否则,内存占用越来越高。轻则影响系统性能,重则导致进程崩溃。
不再用到的内存,没有及时释放,就叫做内存泄漏。
二、垃圾回收机制
大多数语言提供自动内存管理,减轻程序员的负担,这被称为“垃圾回收机制”(garbage collector)。
最常使用的方法叫做“引用计数”:语言引擎有一张“引用表”,保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放。
三、内存泄漏的识别方法
经验法则,如果连续五次垃圾回收之后,内存占用一次比一次大,就有内存泄漏。这就要求实时查看内存占用。
浏览器,chrome:
- 打开开发者工具,选择Timeline面板
- 在顶部的Capture字段里面勾选Memory
- 点击左上角的录制按钮
- 在页面上进行各种操作,模拟用户的使用情况
- 一段时间后,点击对话框的stop按钮,面板上就会显示这段时间的内存占用情况。
如果内存占用基本平稳,接近水平,就说明不存在内存泄漏。反之,就是内存泄漏了。
命令行:
命令行可以使用Node提供的process.memoryUsage方法。
rss(resident set size):所有内存占用,包括指令区和堆栈
heapTotal:“堆”占用的内存,包括用到的和没用到的
heapUsed:用到的堆的部分
external:V8引擎内部的C++对象占用的内存
判断内存泄漏,以heapUsed字段为准。
四、WeakMap
及时清除引用非常重要。但是,你不可能记得那么多,有时候一疏忽就忘了,所以才有那么多内存泄漏。
最好能有一种方法,在新建引用的时候就声明,哪些引用必须手动清除,哪些引用可以忽略不计,当其他引用消失以后,垃圾回收机制就可以释放内存。这样就能大大减轻程序员的负担,你只要清除主要引用就可以了。
ES6 考虑到了这一点,推出了两种新的数据结构:WeakSet 和 WeakMap。它们对于值的引用都是不计入垃圾回收机制的,所以名字里面才会有一个”Weak”,表示这是弱引用。
const wm = new WeakMap();
const element = document.getElementById('example');
wm.set(element, 'some information');
wm.get(element) // "some information"