首先需要通过工具或命令验证是否存在内存泄漏。常见方法包括:
top/htop命令:实时查看系统内存使用情况,若Node.js进程的RES(常驻内存)持续增长且不回落,可能存在泄漏。pm2进程管理工具:使用pm2 monit监控应用内存,或通过pm2 list查看内存占用趋势。process.memoryUsage():在代码中定期打印内存使用情况(如每10秒一次),观察heapUsed(堆内存使用量)是否持续增加。定位泄漏点是解决问题的关键,常用工具如下:
node --inspect app.js启动应用,在Chrome浏览器访问chrome://inspect,点击“inspect”进入调试界面。切换至“Memory”面板,拍摄堆快照(Heap Snapshot),对比不同时间点的快照,查看“Retainers”(保留树)中占用内存增长的未释放对象(如全局变量、闭包、事件监听器等)。npm install heapdump,在代码中引入并绑定信号触发快照生成(如kill -USR2 <pid>),生成的.heapsnapshot文件可通过Chrome DevTools打开分析,直观查看内存中的对象引用链。npm install memwatch-next,通过memwatch.on('leak', (info) => console.error(info))监听内存泄漏事件,当连续多次垃圾回收后内存未释放时,输出泄漏信息(如内存增长量、堆大小)。根据分析结果,针对性解决以下常见泄漏问题:
global.xxx = ...),使用let/const声明局部变量,或在不需要时手动删除(如delete global.xxx)。function outer() { const bigData = [...]; return function inner() { ... } }),若inner函数长期存在,bigData无法被回收,需优化闭包逻辑(如将bigData移至函数内部或及时置空)。setInterval/setTimeout时,在组件销毁或逻辑结束时调用clearInterval/clearTimeout(如const timer = setInterval(...); // 不需要时 clearInterval(timer))。EventEmitter或DOM事件(如element.addEventListener),在不需要时调用removeListener/off(如emitter.removeListener('event', listener)),避免重复绑定导致内存堆积。Map/Set),设置合理的过期时间或大小上限(如lru-cache模块),定期清理过期数据。fs.readFileSync),改用fs.createReadStream逐块读取(如readStream.pipe(writeStream)),减少内存峰值。Object pool模式),避免在循环中频繁创建新对象(如for (let i = 0; i < 1000; i++) { const obj = {}; })。--max-old-space-size参数增加堆内存限制(如node --max-old-space-size=8192 app.js,设置为8GB),避免因内存不足导致进程崩溃。global.gc()手动触发垃圾回收(需启动时添加--expose-gc参数,如node --expose-gc app.js),但需谨慎使用(避免频繁调用影响性能)。clinic heapprofiler -- node server.js启动分析,Ctrl+C停止后生成可视化火焰图。火焰图中宽且持续的矩形代表内存占用高的函数调用,可快速定位泄漏点(如某函数持续创建未释放的对象)。valgrind --tool=memcheck --leak-check=full node app.js检测内存泄漏,输出详细的泄漏信息(如泄漏的内存地址、调用栈),适合底层内存问题排查(如C++插件泄漏)。swapon命令增加交换空间(如sudo fallocate -l 2G /swapfile,sudo chmod 600 /swapfile,sudo mkswap /swapfile,sudo swapon /swapfile),缓解内存压力,但需注意交换空间会降低性能。systemctl list-unit-files --type=service查看运行中的服务,关闭未使用的服务(如sudo systemctl stop <service-name>),释放系统内存资源。