1. 监控内存使用情况
监控是优化的基础,需通过工具实时掌握内存消耗趋势。
process.memoryUsage()获取进程内存占用详情(如heapUsed、heapTotal、rss),通过console.memoryUsage()打印到控制台;pm2 start app.js --max-memory-restart 4096M);Heapdump生成V8堆快照(npm install heapdump),用于分析内存泄漏;top、htop、free -m实时查看系统内存使用,vmstat监控内存交换情况,/proc/<pid>/status获取进程详细内存信息。2. 调整V8引擎内存参数
V8是Node.js的JavaScript引擎,其内存管理直接影响应用性能。
--max-old-space-size限制老生代(存储长期对象)内存大小(如--max-old-space-size=4096设置4GB),避免因内存耗尽导致进程崩溃;--max-semi-space-size设置新生代(存储短期对象)内存大小(如--max-semi-space-size=512设置512MB),优化短期对象的垃圾回收效率;--trace_gc或--print-gc参数记录垃圾回收日志,分析GC频率和耗时,针对性优化内存分配。3. 代码层面优化
代码是内存使用的根源,需避免常见的内存泄漏和低效操作。
let/const替代var,避免意外挂载到global对象;stream、timer或eventEmitter不再使用时,调用removeListener或off方法;WeakMap/WeakSet存储临时数据(不会阻止垃圾回收);close()方法释放。stream(如fs.createReadStream)逐块读取大文件,避免一次性加载到内存;Map替代普通对象提高查找效率),避免存储冗余数据;lru-cache实现内存缓存(设置max和maxAge限制缓存大小和有效期),高频数据用Redis等分布式缓存分担内存压力;4. 利用集群模块(Cluster)
Node.js是单线程的,集群模块可利用多核CPU,将负载分散到多个工作进程,减少单个进程的内存压力。
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
for (let i = 0; i < numCPUs; i++) {
cluster.fork(); // 创建子进程
}
cluster.on('exit', (worker) => {
console.log(`Worker ${worker.process.pid} died`);
cluster.fork(); // 自动重启子进程
});
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World\n');
}).listen(8000);
console.log(`Worker ${process.pid} started`);
}
通过这种方式,多核CPU可同时处理请求,提升整体吞吐量并降低单个进程的内存占用。
5. 使用进程管理工具
进程管理工具可简化内存监控和管理,提高应用稳定性。
--max-memory-restart)、自动重启(内存超过阈值时重启)、集群模式(pm2 scale app 4启动4个实例);MemoryLimit参数)和自动重启。6. 系统级优化
系统配置可提升Node.js的内存使用效率。
ulimit -n 65535);sudo swapon /swapfile);docker run -m 4g --memory-swap 4g app),防止应用占用过多宿主机内存;7. 分析与调试内存泄漏
内存泄漏会导致内存持续增长,需通过工具定位和修复。
heapdump在可疑代码处生成堆快照(heapdump.writeSnapshot('/path/to/snapshot.heapsnapshot'));Memory面板加载堆快照,比较不同时间点的快照,查找内存持续增长的对象(如未被释放的闭包、全局变量);memwatch-next监听内存泄漏事件(memwatch.on('leak', (info) => { ... })),生成堆快照辅助分析。8. 优化依赖包
第三方依赖包可能隐藏内存问题,需谨慎选择和管理。
npm audit检查依赖包的安全性和性能问题,移除不必要的依赖;lodash.get替代整个lodash),降低内存占用。