内存溢出及处理
最近出现了一个问题,某次代码改动后,用户反馈浏览器可能卡死,或者点不动,基本判断是某个操作造成内存溢出,浏览器卡死。详细分析如下。
问题分析思路
1、如果一个新功能造成的 bug,造成浏览器直接崩溃,无法获取内存信息,也无法获取页面统计。因为新功能代码确定,可以从代码层面,白盒检查,二分法检查,分段排查代码中的问题。同时减少数据量量级,避免浏览器直接卡死的问题。
2、如果是未知原因造成的 bug,无法直接定位出错的功能和模块,可以在浏览器中调试。浏览器控制台 Performance 中,下面的属性可以参考:
screenshot 录屏:记录界面不同阶段的录屏,一般用于定性分析。
判断时间轴中 longtask 长任务,耗时超过 100ms,有问题通常红色标明,这个就反映了掉帧和界面卡顿。
Memory 内存:可以记录 Js heap, documents, nodes, listeners, GPU memory,反映了不同的消耗。
可以根据上述参数,先定性分析问题的大致方向。
具体案例分析
内存泄露堆栈溢出的本质问题
-
算法问题
- 循环引用
- 循环过多
- 闭包泄露 数据问题
- 数据量很大
- 脏数据、异常数据
- 数据类型不对
最后发现,代码中使用了 O(n ^ 2) 的时间复杂度,内循环中有大量消耗内存的函数。用户数据量可能上万,可能执行了上亿次调用函数操作,造成内存溢出。
let len = 10000;
for (let i = 0; i < len; i++) {
for (let j = 0; j < len; j++) {
fn(); // fn 是一个开销很大的函数
}
}
解决办法:避免在循环内部处理开销很大的操作,在循环外部提前算好,循环内部使用 map 形式获取计算结果,问题解决。
修改后的数据分析