面试题答案
一键面试利用Node.js内置工具分析内存使用情况
process.memoryUsage()
- 这是Node.js内置的获取当前进程内存使用情况的方法。在Express应用代码中,可在关键位置添加如下代码:
const express = require('express'); const app = express(); app.get('/memory', (req, res) => { const memoryUsage = process.memoryUsage(); res.json(memoryUsage); }); const port = 3000; app.listen(port, () => { console.log(`Server running on port ${port}`); });
- 通过访问
/memory
接口,能获取到rss
(resident set size,进程占用的物理内存大小)、heapTotal
、heapUsed
等内存使用数据,初步了解内存使用趋势。
console.memory
(实验性)- 在支持的环境中,可在Node.js REPL或应用代码中使用。在Express应用启动前添加如下代码:
console.memory();
- 它会输出当前的JavaScript堆内存使用情况,可用于观察内存的变化。
利用第三方工具分析内存使用情况
- Node.js core - profiler
- 安装:
npm install @node - js/core - profiler
- 使用:在Express应用中添加如下代码:
const profiler = require('@node - js/core - profiler'); const express = require('express'); const app = express(); profiler.startProfiling(); app.get('/startProfile', (req, res) => { profiler.takeSnapshot('snapshot1'); res.send('Snapshot taken'); }); app.get('/stopProfile', (req, res) => { profiler.stopProfiling(); res.send('Profiling stopped'); }); const port = 3000; app.listen(port, () => { console.log(`Server running on port ${port}`); });
- 通过访问
/startProfile
接口获取内存快照,可在node_modules/@node - js/core - profiler/results
目录下找到生成的.cpuprofile
文件,使用Chrome DevTools等工具打开分析内存使用情况。
- 安装:
- Chrome DevTools
- 启动应用并连接:使用
node --inspect=0.0.0.0:9229 app.js
启动Express应用(假设应用入口文件为app.js
)。 - 打开Chrome DevTools:在Chrome浏览器中访问
chrome://inspect
,点击Open dedicated DevTools for Node
。 - 录制内存快照:在DevTools的
Memory
面板,点击Take snapshot
,可获取应用当前的内存快照。多次获取快照并对比,观察对象的增减情况。 - 分析内存泄漏:查找那些在多次快照中持续增长且不应增长的对象,可能就是内存泄漏的源头。
- 启动应用并连接:使用
定位内存泄漏问题
- 查找未释放的引用:通过上述工具,若发现某些对象持续占用内存且不断增长,检查代码中是否存在对这些对象的不合理引用。例如,在Express路由处理函数中,若有全局变量引用了大量数据且未及时清理,就可能导致内存泄漏。
- 事件监听器未移除:若应用中使用了事件监听器,确保在不再需要时正确移除。例如:
const eventEmitter = new require('events').EventEmitter(); const handler = () => { console.log('Event fired'); }; eventEmitter.on('event', handler); // 不再需要时移除监听器 eventEmitter.removeListener('event', handler);
- 若未移除,随着事件不断触发,相关处理函数可能会导致内存不断增加。
优化方案
- 优化数据结构:使用更高效的数据结构,例如用
WeakMap
代替普通Map
,若对象的引用不需要强引用时,WeakMap
中的键值对在键对象不再被其他地方引用时会被垃圾回收机制回收,从而减少内存占用。 - 及时释放资源:在处理完大文件、数据库连接等资源后,及时关闭或释放它们。例如,使用
fs
模块读取大文件后,确保调用fs.close()
关闭文件描述符。 - 优化缓存策略:如果应用使用缓存,设置合理的缓存过期时间。例如在Express应用中使用
express - cache - response
中间件,设置合适的expires
时间,避免缓存数据无限增长占用过多内存。