JavaScript垃圾回收机制是自动运行的。原理:在回收内存时,首先会判断该对象是否被其它对象引用(即:判断对象是否在执行活动对象和作用链中)。在确定没有其它对象引用便释放该对象内存区域。JavaScript不会回收任何正在运行脚本申请的内存。
一、 内存分配方式。
静态分配:全局变量和函数的分配方式,页面没有关闭之前,不会被清除的。
自动分配:局部变量的分配方式,不是动态分配的局部变量就是自动分配的。
动态分配:使用new实例对象的局部变量是主动要求分配内存空间的。
举例介绍活动对象和作用域域链:
function aa(){this.qq = "XXX";}
function bb(){this.pp = "YYY";}
function cc(){var a1 = new aa();var b1 = new bb();return b1;}
var b1 = cc();
alert(b1.pp);
执行cc()时,cc的执行环境会创建一个活动对象和一个作用域链。
window<=>cc<=>a1<=>rr
window<=>cc<=>b1<=>rr
1. cc的活动对象包括a1和b1,其作用域链是window
2. a1的活动对象包括rr,其作用域链是cc
3. b1的活动对象包括rr,其作用域链是cc
当cc()执行完毕后,执行环境会尝试回收活动对象占用的内存。但因局部变量b1 通过return b1,为其增加了一条作用域链:window<=>b1<=>rr,所以GC停止对b1回收。
二、 垃圾回收机制
1. 标记清除
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后它会去掉在正执行的活动对象和作用链中的变量的标记。剩下被加上标记的变量将被删除,因为活动对象已经无法访问到这些变量。最后垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
function cat(name){
var zhuren ;
this.name = name;
this.addZhuRen = function(m){zhuren = m;}
this.getZhuRen = function(){return zhuren;}
}
function owner(name){this.name = name;}
var someone = new owner("zhangsan");
var somecat = new cat("asan");
somecat.addZhuRen(someone);
//将对象some.name赋值给实例对象somecat方法addZhuRen
someone = null ;
//实例对象someone的变量和方法动态分配的内存被释放
alert(somecat.getZhuRen().name);
//实例对象somecat的局部变量zhuren没有被释放
2. 引用计数
跟踪记录每个值被引用的次数。当声明一个变量并将引用类型的值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1.相反,如果包含对这个值引用的变量又取得另外一个值,则这个值的引用次数减1.当这个值的引用次数变成0时,则说明没有办法访问这个值了,因此就可以将其占用的内存空间回收回来。
引用计数法引出的内存泄露严问题:
1. 相互引用/循环引用
function A(){this.x;}
function B(){this.y;}
var obja=new A();
var objb=new B();
obja.x=objb;
objb.y=obja;
obja和objb各自的属性相互引用(两个对象的引用次数都是2)。 在采用引用计数策略中,函数执行完毕,objectA和objectB继续存在,因为他们引用次数永远不会是0。在完成使用后加入下代码,释放对象内存:
obja.x = null;
obja.y = null;
同理:对象自引用/闭包相互引用
function A(){this.a;}
var obja=new A();
obja.a=obja;
function leak(){
var o = function(){};
function closure(){};
o.f = closure;}