对于本地可复现的进行调试
使用 ab
指令可以在本地进行压测,如:
1 | ab -n 2000 -c 100 http://localhost:8090/home |
然后通过 --inspect
指令链接 chrome 调试器进行调试:
1 | node --inspect --heapsnapshot-signal=SIGUSR2 ./server.js |
--heapsnapshot-signal=SIGUSR2
表示接收到 SIGUSR2 信号时生成堆内存快照。
然后使用浏览器访问 chrome://inspect/#devices,点击 inspect:
弹出调试面板后就可以在 Memory 选项卡下生成堆快照了:
通常我们可以在项目启动时进行一次快照生成,然后在压测完成后再生成一个快照,在选项卡中选择展示两个快照的对比结果,就能展示出来压测后新创建的内存信息,这里的排序通常按照 Retained Size
表示当前对象及自身所占的内存其引用对象的总内存:
上面结果中发现 array 类型和 string 类型的数据内存占用很大,比较可疑,可以对其进行展开操作,并展示其具体值:
由上图的对象信息可以查看到其创建对象的变量名、以及调用位置:
我们对变量和函数名称进行查找,就能发现具体原因是因为创建了一个未销毁的全局变量:
对于线上存在的内存溢出问题
为了防止内存溢出我们应该做什么?
- 注意全局变量;
- 内存溢出的本质就是对象被占用,只要确保对象没有没持续引用,哪怕是控制台输出其都是一个被占用的状态;
- 为某个对象添加重复的监听事件也可能导致内存不被销毁;
- 避免使用匿名函数,这会让代码调试变得很难,调试时也注意关闭 terser 等代码压缩和混淆;
- TODO 。。。