前言
我们知道,同步的递归写法,如果在退出递归条件失效时,会快速因为栈溢出导致进程挂掉。而在某些场景下,我们会采用异步的递归写法来规避这个问题:
async function recursive() {
if( active ) return;
// do something
await recursive();
}
关键字 await 后面的函数调用可能会跨越多个 event loop,这样的写法下不会出现栈溢出的错误。然而这种写法其实也不是万无一失的,我们来看下面这个生产故障案例。
发现问题
客户接入 Node.js 性能平台 后,通过监控经常出现内存增长导致的 OOM,于是客户加上了一条告警规则:@heap_used / @heap_limit > 0.5,目的是在堆较小但是发生泄漏时能正常输出 heapsnapshot 文件用于分析。
我有几张阿里云幸运券分享给你,用券购买或者升级阿里云相应产品会有特惠惊喜哦!把想要买的产品的幸运券都领走吧!快下手,马上就要抢光了。
经过授权,我们得以进入客户的项目,看到获取到的 heapsnapshot 文件,与此同时,可以通过进程趋势图看到内存飙高引发的一些“并发症”,比如 GC 耗时变久,降低了进程的处理效率:
定位问题
借助这次顺利生成的堆快照(heapsnapshot)文件,大致能看出内存泄漏的地方在哪里,但想要完全找出来,还有点难度。
堆快照分析
第一个信息,内存泄漏报表: