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 语句

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

相关推荐
谁呛我名字1 小时前
大数据应用开发——数据可视化
javascript·vue.js·echarts
前端郭德纲1 小时前
浅谈React的虚拟DOM
前端·javascript·react.js
ComPDFKit3 小时前
使用 PDF API 合并 PDF 文件
前端·javascript·macos
yqcoder3 小时前
react 中 memo 模块作用
前端·javascript·react.js
谈谈叭3 小时前
Javascript中的深浅拷贝以及实现方法
开发语言·javascript·ecmascript
优雅永不过时·4 小时前
Three.js 原生 实现 react-three-fiber drei 的 磨砂反射的效果
前端·javascript·react.js·webgl·threejs·three
爱编程的鱼4 小时前
javascript用来干嘛的?赋予网站灵魂的语言
开发语言·javascript·ecmascript
神夜大侠6 小时前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱6 小时前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js
柯南二号7 小时前
HarmonyOS ArkTS 下拉列表组件
前端·javascript·数据库·harmonyos·arkts