通过Node.js内置的process.memoryUsage()方法,定期记录内存使用数据(如常驻内存rss、堆内存heapUsed等),观察是否持续增长(无下降趋势)。例如:
setInterval(() => {
const memory = process.memoryUsage();
console.log(`RSS: ${(memory.rss / 1024 / 1024).toFixed(2)}MB, HeapUsed: ${(memory.heapUsed / 1024 / 1024).toFixed(2)}MB`);
}, 5000); // 每5秒打印一次
若内存持续增长,可能存在泄漏。也可使用top、htop或pm2 monit(PM2的监控模块)实时查看Ubuntu系统中Node.js进程的内存占用。
使用heapdump模块在代码中生成堆内存快照(.heapsnapshot文件),或在运行时通过信号触发。例如:
const heapdump = require('heapdump');
// 手动生成快照(指定路径)
heapdump.writeSnapshot('/tmp/snapshot-' + Date.now() + '.heapsnapshot');
// 或通过SIGUSR2信号触发(需启动时允许信号)
// kill -USR2 <pid>
堆快照会记录当前内存中的所有对象及其引用关系,是分析泄漏的关键数据。
node --inspect app.js;chrome://inspect/#devices;通过日志和堆快照结果,检查代码中以下常见泄漏场景:
global.userCache = {}),导致对象无法被GC回收;function outer() { const bigData = [...]; return function inner() { console.log(bigData); } }),外部变量无法释放;emitter.on('event', listener)未调用emitter.removeListener,导致监听器持续占用内存;Map或数组缓存数据时,未设置最大容量或过期时间,导致缓存无限增长。const memwatch = require('memwatch-next');
memwatch.on('leak', (info) => {
console.error('Memory leak detected:', info); // 输出泄漏详情
});
clinic heapprofiler -- node app.js # 收集数据
clinic heapprofiler --visualize-only profile.heapprofile # 生成火焰图
火焰图中宽且持续的矩形代表内存占用高的函数,需重点关注。使用负载测试工具(如autocannon、artillery)模拟高并发请求,观察内存使用是否随请求增加而异常增长。例如:
autocannon -c 100 -d 30 http://localhost:3000/api # 100并发,持续30秒
结合日志和堆快照,分析高负载下的内存变化,找出压力场景下的泄漏点。
通过以上步骤,可系统性地通过Ubuntu下的Node.js日志和工具定位内存泄漏,逐步缩小范围至具体代码段。