1、总述:
JS同Java语言一样,都具有垃圾自动回收机制。即执行环境负责管理代码执行过程中使用的内存:垃圾回收器每隔一定时间周期性地找到那些不再继续使用的资源,并且将它们释放,具体在执行的过程中,垃圾回收器面对局部变量和全局变量时,对它们分别进行跟踪标记,对不在使用的变量标记,以便将来释放它;
2、标记方法:
-
标记清除:
JS中最常用的垃圾收集方式是标记清除,当变量进入环境时将它们标记为“进入环境”,离开时则标记为“离开环境”;
标记策略:垃圾收集器在运行的时候会给所有内存中的变量都加以标记,而后去掉环境变量以及被环境变量引用的变量的标记,在此之后仍旧被标记的变量被视为准备删除的变量,因为环境已经无法再来访问它们,最后,垃圾收集器完成内存清除工作,销毁那些标记的值并回收它们所占据的内存空间。
这种方法流行使用于主流浏览器中(Chrome / IE / Safari / Opera / Firefox),但各自有各自的实现方法;
-
引用计数
该方法并不常用,单Java语言中的回收机制也涵盖了它,关于引用计数的原理:跟踪记录每一个值被引用的次数,如果一个变量声明后采取了赋值操作(var a = “helloWorld”;),则该值被引用的次数为1,如果该值又被赋给另一个变量(var b = “helloWorld”;)则引用次数加1;反之,如果包含该值引用的变量又取了另一个值(a = “another”;)则该值(”helloWorld”)的引用次数减1;当引用的次数变为0时,则表示已经无法访问到这个值,因此,该值就可以被垃圾收集器回收了。
存在问题:循环引用,使得垃圾收集器无法回收它,具体情况如下:
funcion error(){
var objA = new Object();
var objB = new Object();
objA.attribute = objB;
objB.attribute = objA;
}
对于error函数而言,它的内部存在互相引用的现象;当函数结束后,它们的引用次数依旧是2,所以不能被释放掉,如果该函数被多次调用,对于内存的压力可想而知,后果自然严重;(目前IE中的COM⌈¹⌉仍在使用该方法);
解决方法:手动释放创建的循环引用:
objA.attribute = null;
objB.attribute = null;
3、内存问题
在实际应用中,内存存在着分配问题,即内存是有限的:
- 对于垃圾回收器来说,回收间隔时间就显得格外重要,回收时所依据的准则,决定了回收器的效率;
- 分配给Web浏览器的内存少于桌面应用程序的,这样做可以防止因为浏览器中Js的网页耗尽全部的内存,导致系统崩溃,所以优化内存时,一旦数据不再使用,便将其设置为null,即解除引用(适用于全局变量和全局对象的属性),解除后,该值即脱离了执行环境,可以被回收。
4、一些补充:
- 关于COM的垃圾回收解决方法:
1、带外终止(out-of-band termination),对象暴露一个方法,该方法调用时迫使该对象放弃对其它对象的全部引用。
2、身份分离(split identity)技术,一个实现暴露两个单独的COM对象(也称作identity),之间保持弱关联。
5、参考资料:
- 《JavaScript高级程序设计》 Nicholas C.Zakas 著 人民邮电出版社;
- 维基百科—-COM组件的介绍。