1. Heap
Heap 分为young generation, old generation.
- young generation, 采用清除算法,分为from, to两个区域。当需要GC时,会检测分配的对象的有效性,如果从这次GC中存活,会标记,然后copy到to 区域,清空from区,然后交换from, to的命名。当有对象在2次GC都存活了,那么会移动到old generation.这个也被称为minor GC.
- old generation, 采用mark-sweep方法, old generation中allocate分配容易,清理难。这个也被称为major GC。这里的GC也有两种可能,一种是内存充裕时使用mark-sweep, 另一种是内存不充足时内存压塑,移动内存,释放内存碎片。
Usually, ~20% of the Young Generation survives into the Old Generation. Collection in the Old Space will only commence once it is getting exhausted. To do so the V8 engine uses two different collection algorithms:
- Scavenge collection, which is fast and runs on the Young Generation,
- Mark-Sweep collection, which is slower and runs on the Old Generation.
node GC时会stop the world,代表主线程被暂停了。
2. 取得Heapsnap
2.1 heapdump
使用第三方库heapdump
1 | heapdump.writeSnapshot(SNAP_DIR_PATH + '/' + Date.now() + '.heapsnapshot'); |
2.2 node自带的v8模块
这个要node版本14以上才有
1 | function dump(){ |
2.3 node –inspect
1 | node --inspect=0.0.0.0:9229 src/index.js |
打开chrome, 输入chrome://inspect,然后打开DevTools去连接node进程。
3. Chrome DevTools
- GC Root, 比如system context, 是native侧对JS Object的Handle
- distance, 是GC Root到此Object的距离
- shallow size: 自身占有的内次大小,以字节为单位
- Retained size: 由于此对象引用而占有的内存总大小,自己作为dominator占有的大小,以字节为单位。
- Dominators: 支配树,支配树标识了支配者,不同于依赖图,它代表了唯一的支配者:从GC Root到当前节点必由之路。
- Retainers: 自己作为Retainer的视图,自己作为被引用对象的树,从子节点到GC Root。
3.1 Summary 视图
可以展开任意的节点,可以看到它的retainer size和distance, 如果同类型的这两个值想差很大,那么有问题发生。
3.2 Comparison
对比两个视图,然后对delata进行排序,找出其中的异常。
4. 内存泄漏类型
内存泄漏的本质是生命周期长的引用生命周期短的,导致生命周期短的不能按预期被释放。
4.1 被全局变量引用
全局变量的生命周期是程序的周期,所以被全局变量引用,它就不能被释放。
4.2 被单例实例引用
单例也是程序的生命周期,比如express中的依赖注入,如果变量别单例引用,也会有这个问题。
4.3 被clourse引用
因为闭包会引用函数内部的变量,同一个函数的多个闭包会共享内部的变量。闭包会导致函数内部变量不会释放,而且要注意有多个闭包时,它们生命周期不同导致的函数内部变量没有被释放。
这个是发现难度最大的泄漏,要对clourse的内存模式很熟悉后才能分辨出。
4.4 Tips
- 如果distance太大了,达到了几百,那么存在循环引用。
- node默认heap大小是1.5G,可以设置node的启动参数,由于node会按需要GC,当有空间时并不会及时清除old generation。
- dump的之前去掉所有的断点,不然那会影响dump的结果
5. Low-Level Tools
5.1 mdb
这个工具可以debug操作系统,系统crash,用户进程,用户进程的core dump,和对象文件。
5.2 gcore
可以在程序运行时dump程序的core dump。
Reference
https://developer.chrome.com/docs/devtools/memory-problems/memory-101/
https://blog.risingstack.com/finding-a-memory-leak-in-node-js/
https://medium.com/@wavded/how-to-heap-snapshots-aac9284d5329
https://blog.csdn.net/QcloudCommunity/article/details/121026553
https://marmelab.com/blog/2018/04/03/how-to-track-and-fix-memory-leak-with-nodejs.html
https://www.freesion.com/article/7314103000/
https://www.bookstack.cn/read/node-in-debugging/2.2heapdump.md
https://www.freesion.com/article/7314103000/
https://www.cnblogs.com/xieqianli/p/12619886.html
视频
https://www.bilibili.com/video/BV1hS4y1g7U3?spm_id_from=333.999.0.0
https://www.bilibili.com/video/BV1kF411x7JZ?spm_id_from=333.999.0.0