▒ 目录 ▒
- 🛫 导读
- 需求
- 开发环境
- 1️⃣ 艰难的排查过程
- 1. 程序闪退
- 2. 确定为内存泄漏
- 3. 误入歧途
- 4. 二分法注释代码
- 5. 猿脑猜想
- 2️⃣ 排查
- procexp.exe
- Performance 和 Memory
- 3️⃣ 剔除生产环境中的console.log
- webpack插件terser-webpack-plugin
- 🛬 文章小结
- 📖 参考资料
🛫 导读
需求
最近公司使用electron中出现内存泄漏的情况。经过n天的努力,最后定位到
console.log
的问题。
这好像不是第一次遇到类似的问题,特此记录,以敬后效。
开发环境
版本号 | 描述 | |
---|---|---|
文章日期 | 2023-11-04 | |
操作系统 | Win10 - 22H2 | 19045.3570 |
1️⃣ 艰难的排查过程
1. 程序闪退
开发过程中程序一切运行正常,到了测试那里,出现崩溃情况。
多次尝试发现半个小时左右就崩溃了,多个电脑都是这样的。
2. 确定为内存泄漏
一开始一直以为是自己开发的node模块代码异常,导致崩溃。
后来看了下任务管理器的内存,发现某个render进程
内存螺旋式上升,积累到半个小时候就崩溃了。
结论:
- 内存泄漏导致崩溃
- 大概率不是node模块导致的,因为是render进程不断的增大。
3. 误入歧途
排查问题最笨的思路就是注释代码。由于各种原因,我们也是这条路排查的。
当我们注释掉某封包
逻辑后发现一切运行正常。于是猜测是封包的库导致的问题,当即想的是换个库试试。
4. 二分法注释代码
后来某大佬说,可能是用法不对,逐步注释代码试试。然后二分法注释代码,最后在
WebSocket
的某回调函数内发现,注释了console.log
,让一切恢复正常了。
5. 猿脑猜想
该代码会将接受的内容(3Mb左右的
对象
)打印出来,最后发现该对象未被释放。至于为何未释放,这里也只留下几个猜想:
WebSocket
回调函数对该对象进行了引用,导致GC不能释放。WebSocket
回调函数对该对象进行了缓存(方便后续调用),缓存队列巨大(上千的长度),chrome内存是有上限的(各个版本不一样的,我们用的x86的,据说在2G左右),达到上限的时候,还未出发其内存回收。
2️⃣ 排查
procexp.exe
作为专业的windows工具
procexp.exe
,提供了查看内存变换的功能,我们可以通过它看到一些内存上的规律。
小编遇到的问题,可以在这上面发现,每2秒,内存增加3Mb左右。这个大小刚好是我们传递的某个对象,通过它能快速定位问题。
procexp.exe默认没有显示
Private Delta Bytes
选项,我们通过下面的步骤打开该列。
- 右键表头,打开
对话框
2.选择Process Memory
标签页,然后选择Private Delta Bytes
选项
- 模拟内存增长:
如下图,不断的执行window.___=[]; ___.push(new Array(2*1000*1000));
,可以查看到内存增长!
ps: windows自带的
任务管理器
也有类似的功能(貌似win11
后的某个新版本才有的)。
Performance 和 Memory
这个操作就很
专业
了,具体细节很多,小编发现一篇很不错的文章:《console.log 一定会导致内存泄漏? 》https://juejin.cn/post/7185501830040944698,这里就不画蛇添足了,有兴趣的直接看该文章即可。
3️⃣ 剔除生产环境中的console.log
webpack插件terser-webpack-plugin
erser-webpack-plugin 是一个 Webpack 的插件,它主要用于对 JavaScript 代码进行压缩和优化。
它通过使用 Terser 这个 JavaScript 压缩库,来实现对 JavaScript 代码的压缩和优化。Terser 是一个非常强大的压缩库,它能够减小 JavaScript 代码的体积,并提高代码的运行效率。
terser-webpack-plugin 插件的使用非常简单,只需要在 Webpack 的配置中添加这个插件,并设置相关的选项即可。可以进行如下配置,保证生成环境中不包含console系列函数:
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
// 你的压缩选项
compress: {
// drop_console为true时,将删除所有console的函数
drop_console: process.env.NODE_ENV==='production',
drop_debugger: true,
pure_funcs: ["console.log", "console.warn"]
}
}
}),
],
},
};
🛬 文章小结
首先,我们需要明确一点,console.log 本身并不会造成内存泄漏。内存泄漏是指在程序运行过程中,一些不再需要的对象或资源仍然被占用,导致内存无法被释放,从而导致程序运行缓慢或崩溃。
我们来分析一下可能导致内存泄漏的原因。主要有以下几种可能:
- 闭包:如果在 console.log 中使用了闭包,并且该闭包中引用了外部的变量或对象,那么这些变量或对象就不会被垃圾回收器回收,从而导致内存泄漏。
- 对象池:如果在代码中使用了对象池技术,例如Pool 或cache,那么这些对象可能会被长期占用,从而导致内存泄漏。
- 循环引用:如果在代码中存在两个或多个对象之间的循环引用,例如A引用了B,B引用了A,那么这些对象就不会被垃圾回收器回收,从而导致内存泄漏。
综上所述,console.log 本身并不会造成内存泄漏。但是,如果在代码中使用了不当的闭包、对象池或循环引用,那么这些因素可能会导致内存泄漏。
因此,在编写代码时,我们需要注意避免这些问题,以保证程序的稳定性和性能。而且尽可能的别让 console.log 上生产!
。
📖 参考资料
- console.log 一定会导致内存泄漏?不打开 devtools 就不会 https://juejin.cn/post/7185501830040944698
- 千万别让 console.log 上生产! https://juejin.cn/post/7185128318235541563
ps: 文章中内容仅用于技术交流,请勿用于违规违法行为。