Skip to content

Console 导致的内存泄漏

Published:

前言

在开发过程中,我们很多人喜欢用 console.log 来调试代码,查看变量或者函数的输出。但是需要注意到,在项目中使用 console.log 语句时,VSCode 可能提示你“Unexpected console…” 的错误?这其实是因为 Eslint 认为在生产环境中使用 console.log 不是一个好习惯。

原因分析

根据 Eslint 的官方文档console.log 通常用于调试,在开发过程中非常有用,但在生产环境中则不太合适。原因之一是 console.log 可能导致内存泄漏

举个例子:我们有以下的代码:

function handleClick() {
  const arr = new Array(100000).fill(0);
  console.log(arr);
}

在这个例子中,arr 是一个包含 10 万个元素的数组。通常情况下,这个数组在函数执行完毕后会被销毁,JavaScript 的垃圾回收机制会将其回收。但如果我们使用 console.log(arr),这个数组就不会被立刻回收,因为它已经被 console.log 使用。

为了验证这个问题,我们可以使用浏览器的性能分析工具。假设我们在页面上有一个按钮,每点击一次就会执行 handleClick 函数,并打印一个 10 万个元素的数组。如果我们点击了几次按钮,然后尝试进行垃圾回收,你会发现内存占用没有减少,还是保持在较高水平。

然后我们打开内存,可以看到在我们点击内存回收之后,内存无法回到最初的水平。

为什么呢?因为 console.log 语句打印的变量无法被回收。

试试看不使用 console.log

如果我们把 console.log 语句注释掉,再次运行代码,看看内存回收后又是什么结果?

function handleClick() {
  const arr = new Array(100000).fill(0);
  // console.log(arr)
  return arr;
}

这时候,如果我们再进行内存回收,你会发现内存使用情况恢复到了最初的水平。也就是说,数组在函数结束后成功被回收了。

如何解决这个问题?

Vite.js 移除 console

如果使用 Vite.js 作为项目的打包工具,可以通过配置来移除生产环境中的 console.log 语句。这样一来,就可以在开发过程中方便地使用 console.log 进行调试,但在发布时又不用担心内存泄漏的问题。一个简单的配置示例:

export default defineComponent({ mode }) => {
  return {
    esbuild: {
      pure: mode === 'production' ? ['console.log', 'debugger'] : []
    }
  }
}

参考链接