每小时跑一次的统计任务结束后 heapUsed 上浮 40MB,一天后到 1.1GB。堆快照里最大的对象是一个 Map,引用链指向任务回调里的闭包。乍看像缓存或者权限的锅,追下去往往不是。

node --inspect app.js
node --heapsnapshot-signal=SIGUSR2 app.js

追下去是这么回事:闭包把外层的大对象一起带进了生命周期,只要回调还被定时器或监听器引用,那些数据就释放不掉。任务结束没有解绑,引用一直挂在全局的定时器上。

「闭包内存泄漏」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。

线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。

具体做法是,用 heap snapshot 按 retained size 排序 找到持有者;把闭包需要的数据裁成几个基本类型再传进去;任务结束 clearInterval 并移除监听;别在循环里创建闭包捕获整批数据。

验收就看一点,跑满一天 heapUsed 波动在 60MB 以内 快照里那个 Map 不再出现在 top 列表。

作者 9823189