【每日面试题】垃圾回收机制

87 阅读3分钟

JavaScript 具有自动垃圾回收机制,执行环境会负责管理代码执行过程中使用的内存。

垃圾回收机制有两种方式标记清除和引用清除。

垃圾回收机制的原理

找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间),周期性的执行这一操作。

变量的正常生命周期

局部变量只在函数执行的过程中存在。

在这个过程中,会为局部变量在栈(或堆)内存上分配相应的空间,以便存储它们的值。然后在函数中使用这些变量,直至函数执行结束。

这个时候,局部变量就没有存在的必要了,所以可以释放它们的内存以便于将来使用。

在这种情况下,很容易判断变量是否还有存在的必要;但也不是所有情况都这么容易判断。

垃圾收集器必须跟踪哪个变量有用哪个变量没用,没有的变量会打上标记,方便将来收回它占用的内存。

用于标识无用变量的策略可能会因实现而变化,通常有两种策略。

标记清除 - 常用

当变量进入环境(比如在函数中声明一个变量)时,就将这个变量标记为“进入环境”。

当变量离开环境时,则把变量标记为“离开环境”。

垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(可以使用任何标记方式)。

然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。

而在此之后被加上标记的变量将被是为准备删除的变量,因为在环境中的变量已经无法访问到这些变量了。

最后,垃圾收集器完成内存清除工作。销毁那些带标记的值并回收它们所占用的内存空间。

引用计数 - 不常用

跟踪记录每个值被引用的次数。

当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。

如果同一个值又被赋值给另一个变量,则该值的引用次数加1.

相反,如果包含对这个值的引用的变量又被赋值了另一个值,则这个值的引用次数减1.

当这个值的引用次数变为0时,说明没有办法在访问这个值了,所以这个值占用的内存空间可以被回收。

当垃圾收集器下次再次运行时,它就会释放那些引用次数为零的值所占用的内存。

引用计数存在的问题

在 IE 中访问非原生 JavaScript 对象(如 DOM 元素)时,这种算法会导致问题。 当代码中存在循环引用现象时,“引用计数”算法就会导致问题。

var element = document.getElementById('box');
var myObject = new Object();

myObject.element = element;
element.someObject = myObject;

在这个例子中存在循环引用,即使 DOM 元素从页面中移除,它也不会被回收。

需要手动清除, 最好通过将其的值设置为 null 来释放其引用 - 这个做法叫做解除引用。

myObject.element = null; element.someObject = null;

解除变量的引用不仅有助于消除循环引用现象,而且对垃圾回收也有好处。

为了确保有效地回收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。