console 内存占用的误解

背景

闲来无事想研究下执行 console 是否会导致内存泄漏,写了个简单的例子运行,看到内存占用确实会因为 console 导致增大。后面在网上搜了下,发现蛮多文章都会提到打开 devtools 才会内存泄漏,不打开就不会,是这样么?先下结论:无论打不打开 devtoolsconsole 都会导致内存占用,但应该不算泄漏。

简单例子

在无痕模式下运行,排除插件等干扰因素

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 现象:

  1. 初始化内存占用(totalJSHeapSize) 1,745,973 bytes
  2. 随着执行次数,内存占用越来越高直至 53,572,661
  3. 打开 devtools 后,手动触发 GC,降至 35,656,749
  4. 清空 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
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这篇文章中作者给出的例子可以看到两种情况:

  1. 打开 devtools 内存爆炸
  2. 不打开 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 时需要注意:

  1. 尽量不输出大量内容、不直接输出对象
  2. 打包工具配置构建生产环境自动去除 console 语句

感谢阅读,有疑问或者建议欢迎评论或者私信,一起交流学习。

相关推荐
codingandsleeping2 小时前
重读《你不知道的JavaScript》(上)- 作用域和闭包
前端·javascript
前端风云志4 小时前
TypeScript实用类型之Omit
javascript
烛阴4 小时前
Puppeteer入门指南:掌控浏览器,开启自动化新时代
前端·javascript
芝士加6 小时前
Playwright vs MidScene:自动化工具“双雄”谁更适合你?
前端·javascript
Carlos_sam7 小时前
OpenLayers:封装一个自定义罗盘控件
前端·javascript
前端南玖7 小时前
深入Vue3响应式:手写实现reactive与ref
前端·javascript·vue.js
Yueyanc8 小时前
LobeHub桌面应用的IPC通信方案解析
前端·javascript
麦当_9 小时前
基于 Shadcn 的可配置表单解决方案
前端·javascript·面试
Cutey91610 小时前
使用Canvas实现实时视频处理:从黑白滤镜到高级特效
前端·javascript
前端大卫10 小时前
前端调试太痛苦?这 6 个技巧直接解决 90% 问题!
前端·javascript