nodejs学习笔记——内存泄露问题研究

前言

起因是因为一个项目开发到后期文件数量越来越多,本地环境运行时有时候热重载失败断开服务。网络上绝大多数的解决方案是提高上限,假使通过其他手段定位内存泄漏问题,一般方案就是找那些不被使用又不会被释放的变量,处理了这些变量,问题一般就可以解决了。

vue-cli-service serve 命令会启动一个开发服务器 (基于 webpack-dev-server ) 并附带开箱即用的模块热重载 (Hot-Module-Replacement)。
vue-cli3.0并不支持直接添加--max-old-space-size去提高内存上限,需要安装依赖increase-memory-limit
--max-old-space-size,最大 old space 大小,执行 MarkSweep 回收,默认 1G,单位 MB


基础知识

Node.js 进程的内存管理,都是有 V8 自动处理的,包括内存分配和释放。
在 V8 内部,会为程序中的所有变量构建一个图,来表示变量间的关联关系,当变量从根节点无法触达时,就意味着这个变量不会再被使用了,就是可以回收的了
而这个回收是一个过程性的,从快速 GC (garbage collection) 到 最后的 Full GC,是需要一段时间的。
另外,Full GC 是有触发阈值的,所以可能会出现内存长期占用在一个高值,也可以算是一种内存泄漏;还有一种就是引用不释放,导致无法进入 GC 环节,并且一直产生新的占用,这一般会发生在 Javascript 层面。

所以,定位内存泄漏问题,一般方案就是找那些不被使用又不会被释放的变量,处理了这些变量,问题一般就可以解决了。如果是 Node.js 底层变量不释放,除了提交 issue 等待解决外,只能通过优化启动参数来解决。


流程

  1. 重现问题
    在平时写代码的时候,可以将一些重要环节的参数细节打印在 log 中,以便于我们排查问题。
    在 Node.js 的启动参数中,提供了暴露手动调用 GC 方法的参数,即 --expose-gc。我们用这个参数来启动应用后,就可以在代码中调用 global.gc() 手动触发垃圾回收操作。同时,使用 process.memoryUsage().heapUsed 获取进程运行时所占用的内存。如果 GC 之后,内存依然没有下降,就可以确定是内存泄露了。

  2. 生成内存快照
    taobaofed推荐,至少要生成三次内存快照,才能更好的定位问题。这三次中又一次要在问题出现前生成,之后可以在问题持续的过程中生成两次或更多。
    第一次是为了获取正常情况下的堆栈信息,而在问题出现后,堆栈信息一定会发生变化,有了第一次的信息,我们才好进行后面的比对,过滤一些无用的信息。而后两次的快照,用来比对某一对象的堆栈变化,来确定是否是有问题的对象。

  3. 定位问题
    对于内存快照,有四个视图,Summary、Comparison、Containment、Statistics。其中Comparison可以进行多个快照比对,使用较多。而路径视图可以清楚的分辨对象被哪个变量持有,哪些不存在引用却依然存在的。

  4. 解决问题
    一般在 Javascript 中存在引用而导致内存泄漏的情况,是比较好处理的,只需要在使用后及时的将引用释放掉即可。但如果属于底层机制的问题,如果等不了 bugfix,就只能先通过开篇讲的提高内存上限。


实际问题

taobaofed的同学很好的阐述了解决内存泄露问题的思路,那么回到我们遇到的实际问题:本地环境vue-cli3.0多次热更新后内存溢出。

查看源码,发现其也是简单调用了webpack hot-reload middleware。那么问题的本质就是,node服务因为webpack的一次次热重载且内存泄露导致了JavaScript heap out of memory。引起这个内存泄露的主要原因大概率不是因为webpack,而是存在于 Loaders/Plugins 或是与之相类似的。

这里我们可以借助工具:devtool,heapdump + chrome devTool 或者是 memwatch 去查看内存快照。

解决办法:找到引起问题的依赖或者是代码中会严重引起内存泄露的地方修改。若是依赖的问题,通过git issue和release log查看是否确实存在问题且已经修复再update。


心得体会

虽然起因和node服务内存泄露问题后所差距,但是问题原因和解决思路基本是一致的。相比解决问题,定位排查问题的根源更加困难。同时平时写代码也要多注意内存泄露的问题,养成良好的习惯。


参考

如何定位 Node.js 的内存泄漏
记一次 Node.js 应用内存暴涨分析
webpack Issue 6929

你可能感兴趣的:(nodejs学习笔记——内存泄露问题研究)