JavaScript对内存分配及管理机制详细解析(2)

o2 = “yo”; //  好,现在o2也不引用外层对象了,外层对象引用计数为“0”
// 意味着外层对象可以被“垃圾回收”了
// 然而,内层对象还被oa引用着,因此还是没有被回收 (个人注释:这里有一点闭包的意味)

oa = null; //  现在oa不引用内层对象了
// 内层对象也被垃圾回收

局限:循环引用

看下面代码:

function f(){
var o = {};
var o2 = {};
o.a = o2; // o 引用 o2
o2.a = o; // o2 引用 o

return “azerty”;
}

f();
// o o2两个对象构成了循环引用
// 当函数执行完毕的时候,他们就被关在了f的作用域里面,没有外面的人可以使用他们
// 所以按理说,他们已经没有存在价值了,需要被垃圾回收,释放内存
// 然而,他们的引用计数都不为“0”
// 所以在这种引用计数的机制下,他们没有被回收

实际例子
在IE6,7版本的浏览器中,就是使用的引用计数机制。因此,下面的代码在IE6,7中可以稳稳地发生内存泄漏

var div = document.createElement("div");
div.onclick = function(){
  doSomething();
}; // div的onclick属性,会引用 function
// 然而这个 function 反过来又引用了这个div,因为div在handler的作用域里面。
// 造成上述循环引用,导致内存泄漏。标记清除算法

这种算法把“可以回收”定义成“对象不可达”,即访问不到。

这种算法,会定义一个“根”,并且定期地从“根”出发,找出“根”下面的所有对象,看能不能从“根”找到一条路径引用到这个对象。从不同的“根”出发,垃圾回收程序就可以区分所有对象是不是“不可达”的,当对象“不可达”时候,便被回收。

这种算法比引用计数算法要好些。因为 “一个对象的引用计数是0”可以推出“这个对象不可达”,逆命题则为假。也就是说这种算法扩充了垃圾回收的范围。

循环引用不再是困扰
在上面的循环引用例子中,当函数返回时,o 和 o2都已经不再被任何人引用,也就是“不可达”了,便顺理成章地被垃圾回收掉了。

局限:对象需要明确的“不可达”
虽然说是局限,然而这种情况在实际当中很少发生,因此很少有人关注这一点。

您可能感兴趣的文章:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdzydx.html