背景
闲来无事想研究下执行 console
是否会导致内存泄漏,写了个简单的例子运行,看到内存占用确实会因为 console 导致增大。后面在网上搜了下,发现蛮多文章都会提到打开 devtools
才会内存泄漏,不打开就不会,是这样么?先下结论:无论打不打开 devtools
,console
都会导致内存占用,但应该不算泄漏。
简单例子
在无痕模式下运行,排除插件等干扰因素
html
<html>
<body>
<button id="execute">生成并 console</button>
<div id="msg1"></div>
<div id="msg2"></div>
<script>
// 实时更新内存占用
setInterval(() => {
document.querySelector(
'#msg1'
).innerHTML = `<span>实时: totalJSHeapSize=${window.performance.memory.totalJSHeapSize}, usedJSHeapSize=${window.performance.memory.usedJSHeapSize}</span>`;
}, 1000);
let counter = 0;
// 每次执行更新内存占用
function updateTag() {
document.querySelector(
'#msg2'
).innerHTML = `<span>执行${counter}: totalJSHeapSize=${window.performance.memory.totalJSHeapSize}, usedJSHeapSize=${window.performance.memory.usedJSHeapSize}</span>`;
}
updateTag();
document.querySelector('#execute').addEventListener('click', () => {
const records = [];
for (let i = 0; i < 100000; i++) {
records.push({});
}
console.log(records);
counter++;
updateTag();
});
</script>
</body>
</html>
下图 Gif 现象:
- 初始化内存占用(totalJSHeapSize) 1,745,973 bytes
- 随着执行次数,内存占用越来越高直至 53,572,661
- 打开 devtools 后,手动触发 GC,降至 35,656,749
- 清空 console 后,再次手动触发 GC,再降到 2,151,469
可以看到内存占用增大是在打开 devtools 之前就发生了,尽管后续手动触发 GC 后占用稍减少,但量级没有变化。而在清空 console 面板之后再次触发 GC 后才恢复初始的量级。
网上例子的误解
html
<!DOCTYPE html>
<html lang="en">
<body>
<button id="btn">点我</button>
<div id="box"></div>
<script>
const btn = document.getElementById('btn');
const box = document.getElementById('box');
btn.addEventListener('click', function () {
const MB = 1024 * 1024;
log();
function log() {
const memory = performance.memory.totalJSHeapSize;
const usagedMemory = Math.floor(memory / MB);
box.insertAdjacentHTML('beforeend', `<span>${usagedMemory} </span>`);
const obj = { usagedMemory, str: 'g'.repeat(50 * MB) };
console.log(obj);
setTimeout(() => log(), 50);
}
});
</script>
</body>
</html>
作者:zxg_神说要有光 链接:https://juejin.cn/post/7185501830040944698
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这篇文章中作者给出的例子可以看到两种情况:
- 打开 devtools 内存爆炸
- 不打开 devtools 内存平稳
评论中有赞同也有疑惑和反对的。其实这里关键在于理清 console 和 devtools 之间的关联:
通俗解释,懂的朋友可以帮忙补充下。
- 打开 devtools 时,console 会自动解开打印的对象(1 层)
- 不打开时,console 不会自动解开打印的对象
console.log({a:1,b:{c:2,d:{e:3}}})
不同浏览器可能有不同行为
现在大家心中应该有答案了,其实打开 devtools 之后,由于"自动解开对象"的机制,控制台需要读取并输出大字符串,内存占用自然就会增大;而为什么例子中不打开 devtools 内存没什么变化,其实应该是有变化的,只是可能例子中有几个因素会影响直观:单个对象占用小可能被 Math.floor(n/1024/1024) 舍去;内核对字符串有优化;没有展示其它指标 usedJSHeapSize 等。
小练习,修改网上例子:
const obj = { usagedMemory, str: 'g'.repeat(50 _ MB) };
改成
const obj = { usagedMemory, wrapper: {str: 'g'.repeat(50 _ MB)} };
看下打开 devtools 还会不会炸
结尾
回到结论,确定了 console 会占用内存。那为什么不算泄漏呢,我们要回归 console 的初衷,是用作记录关键日志的,"记"肯定会占用内存(无法白嫖haha)。退一步,如果真的会被垃圾回收,是开发者想要的效果吗?
最后在使用 console 时需要注意:
- 尽量不输出大量内容、不直接输出对象
- 打包工具配置构建生产环境自动去除 console 语句
感谢阅读,有疑问或者建议欢迎评论或者私信,一起交流学习。