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

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

相关推荐
kyriewen6 小时前
别再 console.log 了:5 个 Chrome DevTools 调试技巧,用过就回不去了
前端·javascript·面试
To_OC8 小时前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode
GuWenyue10 小时前
排序效率低?5分钟吃透快速排序,性能飙升至O(nlogn)
前端·javascript·面试
何时梦醒10 小时前
深入理解递归与快速排序 —— 从基础入门到手写实现
前端·javascript
bonechips10 小时前
LLM 的无状态:从 HTTP 协议到对话上下文工程
前端·javascript
胡志辉10 小时前
从 prototype 到 V8,看懂 JavaScript 原型链
前端·javascript
ping某12 小时前
专栏-null 和 undefined 到底是什么?
前端·javascript·后端
swipe15 小时前
从 0 到 1 理解 React 虚拟列表:定高、不定高与 Canvas 版本完整拆解
前端·javascript·面试
铁皮饭盒15 小时前
Bun执行python代码
前端·javascript·后端
zzzzzz31017 小时前
当甲方说'logo放大的同时再缩小一点'时,我用 AI 把这个需求做出来了
javascript·css·程序员