toFrankie / blog

种一棵树,最好的时间是十年前。其次,是现在。
21 stars 1 forks source link

细读 JS | 浅谈内存泄露、内存溢出 #279

Open toFrankie opened 1 year ago

toFrankie commented 1 year ago

配图源自 Freepik

讲真,这两个概念很容易被混为一谈。

一、内存

在 JavaScript 中,没有像 C 语言等提供有内存管理接口,JavaScript 是在创建变量时自动进行分配内存,并且在不使用它们时“自动”释放。释放的过程被称为“垃圾回收”。

这个“自动”就是混乱的根源,并让 JavaScript 开发者错误地认为他们可以不用关心内存管理。

内存的生命周期

不管什么程序语言,内存的生命周期基本是一致的:

  1. 分配你所需要的内存
  2. 使用分配到的内存(读、写)
  3. 不需要时,将其释放/归还

所有语言第二部分都是明确的。第一和第三部分在底层语言中是明确的,但在像 JavaScript 这些高级语言中,大部分都是隐含的。

内存管理的难题

大多数内存管理的问题都在“当内存不需要使用时释放”这个阶段。最困难的就是如何界定并找到“哪些被分配的内存确实不再需要了”。它往往要求开发人员来确定在程序中哪一块内存不再需要并且释放它。

高级语言解释器嵌入了“垃圾回收器”,它的主要工作是跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它。这只能是一个近似的过程,因为要知道是否仍然需要某块内存是无法判定的(无法通过某种算法解决)

垃圾回收(Garbage Collection,GC)

由于一些内存“不再需要”的问题无法判定,因此,垃圾回收实现只能有限制的解决一般问题。

所以,通常我们不会在全局作用域下进行过多的变量或函数声明,更推荐将它们放在立即执行函数表达式(IIFE)内进行声明。否则它们将无法被垃圾回收,即在程序的生命周期内一直存在。

这一小节提到的“对象”,不仅特指 JavaScript 对象,还包括函数作用域、全局作用域。

二、内存泄露、溢出

区别

这两个概念是存在区别的。

当内存泄露积累到一定程度,就会发生内存溢出。而内存溢出导致的结果是应用程序被杀死。

场景

  1. 内存溢出
const obj = {}
for (let i = 0; i < 10000; i++) {
  obj[i] = new Array(1000000)
}
// 将会崩溃
  1. 内存泄露

未完待续...