什么是垃圾
一般来说,没有被引用或访问不到的对象就是垃圾。
垃圾收集机制的原理
JavaScript具有自动垃圾回收机制,其原理是:找出不再继续使用的变量,然后释放其内存。这一操作会按照固定的时间间隔(或代码执行中预定的收集时间)周期性执行。而对于如何找出不再继续使用的变量,有标记清除法和引用计数法两种方法。一旦辨别完毕,这些内存区域即可在未来的分配中重用,或者是返还给操作系统。
标记清除法(主流方法)
介绍
这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。
当变量进入环境(比如在函数中声明一个变量)时,将该变量标记为”进入环境“。当变量离开环境时,将其标记为”离开环境“。最后,垃圾收集器完成内存清除的工作,销毁那些带标记的值并回收他们占用的内存空间。
至于如何标记变量,可以通过翻转某个特殊的位,也可以用两个列表分别存储进入环境的变量和离开环境的变量等。
一些优化
分代回收
对象分为两组:“新对象”和“旧对象”。许多对象出现,完成它们的工作并迅速结束,它们很快就会被清理干净。那些活得足够久的对象,会变“老”,并且很少接受检查。
增量回收
如果有很多对象,并且我们试图一次遍历并标记整个对象集,那么可能会花费一些时间,并在执行中会有一定的延迟。因此,引擎试图将垃圾回收分解为多个部分。然后,各个部分分别执行。这需要额外的标记来跟踪变化,这样有很多微小的延迟,而不是很大的延迟。
空闲时间收集
垃圾回收器只在 CPU 空闲时运行,以减少对执行的可能影响。
限制
那些无法从根对象查询到的对象都将被清除。
引用计数法
此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。
如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。 当声明了一个变量并将一个引用类型的值赋给该变量时,该值的引用次数为1。接着,如果该值又被赋给另一个变量,引用次数+1。如果包含该值引用的变量被赋予了另一个值,引用次数-1。
var a = {m: 1}; // 对象 `{t: 1}` (以下简称obj)被引用一次
var b = a; // obj 被引用两次
a = null; // obj 现在为1次
b = null; // obj 现在为0次,可回收
限制(循环引用)
循环引用时,两个对象都至少被引用了一次,将不能自动被回收。所以导致内存泄露。
如下面的例子所示:
function(){
var a = {m: 1}; // 对象 `{m: 1}` (以下简称obj1)被引用一次
var b = {n: 2}; // 对象 `{m: 1}` (以下简称obj2)被引用一次
a.m = b; // obj1被引用两次
b.n = a; // obj2被引用两次
}
当函数执行完毕后,由于obj1和obj2的引用次数都为2,这两个对象将依然存在而不会被回收。
IE9之前的版本中DOM和BOM对象存在这种问题。
管理内存
为了防止运行JavaScript的网页耗尽全部系统内存而导致系统崩溃,分配给Web浏览器的可用内存数量通常比分配给桌面应用程序的少很多。内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能同时执行的语句数量。
因此,确保占用最少的内存可以让页面获得更好的性能。优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其设置为null来释放引用。
编写代码建议
对于大多数全局变量和全局对象,当不再使用时手动置null,解除引用。
注意:解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用真正的作用是让值脱离执行环境,以便垃圾收集器下次 运行时将其回收。