关于JS垃圾回收机制
一、垃圾回收机制的必要性
由于字符串、对象和数组没有固定大小,所以当它们的大小已知时,才能对它们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便它们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
JavaScript的解释器可以检测到何时程序不再使用一个对象了,当它确定了一个对象是无用的时候,它就知道不再需要这个对象,可以把它所占用的内存释放掉了。
二、垃圾回收机制
Js具有自动垃圾回收机制。垃圾收集器会按照固定的时间间隔周期性的执行。
1、标记清除(常用)
当一块内存中的数据能够被访问时,垃圾回收器就认为"该数据能够被获得"。不能够被获得的数据,就会被打上标记,并回收内存空间。这种方式叫作标记---清除算法。
这个算法会设置一个全局对象,并定期地从全局对象开始查找,垃圾回收器会找到所有可以获得与不能获得的数据。
工作流程:
(1)垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记。
(2)去掉环境中的变量以及被环境中的变量引用的变量的标记。
(3)再被加上标记的会被视为准备删除的变量。
(4)垃圾回收器完成内存清除工作,销毁那些带标记的数据并回收它们所占用的内存空间。
注意:在局部作用域中,当函数执行完毕后,局部变量也就没有存在的必要了,因此垃圾收集器很容易做出判断并回收。但在全局中,变量什么时候需要自动释放内存空间则很难判断,因此我们在开发时,应尽量避免使用全局变量。如果使用了全局变量,则建议不再使用它时,通过释放变量方式,以确保能够及时回收内存空间。
2、引用计数
跟踪记录每个值被引用的次数。例当变量声明,第一次赋值时记为1,然后当这个变量值改变时,记录为0,将计数为0的回收。
工作流程:
(1)声明了一个变量并将一个引用类型的值赋值给这个变量,这个引用类型值的引用次数就是1。
(2)同一个值又被赋值给另一个变量,这个引用类型值的引用次数加1.
(3)当包含这个引用类型值的变量又被赋值成另一个值了,那么这个引用类型值的引用次数减1.
(4)当引用次数变成0时,说明没办法访问这个值了。
(5)当垃圾收集器下一次运行时,它就会释放引用次数是0的值所占的内存。
但是当循环引用的时候就会释放不掉内存。
1 function problem() {2 var objA = new Object();3 var objB = new Object();4 5 objA.someOtherObject = objB;6 objB.anotherObject = objA;7 }
当objA和objB通过各自的属性相互引用,也就是说这两个对象的引用次数都是2。在采用引用计数的策略中,由于函数执行之后,这两个对象都离开了作用域,函数执行完成之后,objA和objB还将会继续存在,因为他们的引用次数永远不会是0。这样的相互引用如果说很大量的存在就会导致大量的内存泄露。
因为IE中的BOM、DOM的实现使用了COM,而COM对象使用的垃圾收集机制是引用计数策略。所以会存在循环引用的问题。
解决:手工断开js对象和DOM之间的链接,赋值为null。IE9把DOM和BOM转换成真正的JS对象了,所以避免了这个问题。