导读:js是高级语言,有自带的垃圾回收器,一般认为js开发可以不用关心内存管理。然而这是错误的。
js垃圾回收算法有两种,其一是引用计数法,其二是标记清除法。
一句话的事儿:
引用计数法:对象有没有其他对象引用到它。如果有,则不回收;如果无,则回收。
标记-清除法:对象是否可以获得。如果可以,则不回收;如果不可以,则回收。
引用计数法:
该算法主要依赖引用的概念,在内存管理环境中,一个对象如果有访问另一个对象的权限,叫做一个对象引用另一个对象。
这是最简单的垃圾回收算法,如果该对象没有其他对象引用,则说明该对象成为了垃圾数据,该对象则会被垃圾回收机制回收。
var o1 = {a: 123, b: 456}; // “这个对象”的引用地址给了o1
var o2 = o1;//o1赋值为o2;“这个对象”的引用地址给了o2
var oa = o2.a; //o1.a赋值给oa
// o1被两处地方引用了,如果这时改变o1和o2的值
o1 = 1; //
o2 = "123"; // 那么现在“这个对象”的引用都不在了,它可以被清除了吗?答案是不可以,因为oa还在引用“这个对象”下的a属性。所以还不能被收回。
oa = "aaa"; // 这时,“这个对象”才会被回收。
那么问题来了,如果我这个对象有循环引用呢?像这样:
function foo(){
var o1 = {}
var o2 = {}
o1.a = o2;
o2.b = o1;
return "foo"
}
foo();
该算法不能处理循环引用的情况,两个对象相互引用,形成一个循环。他们互相至少引用一次,所以他们不会被回收。
实际例子:
在IE6、7使用引用计数方式对dom对象进行垃圾回收
var div = document.getElementById("myId");
div.foo = div;
像这种情况,在IE6、7中,就会存在内存泄漏的问题,即使将来这个dom元素从dom树种删了,这个元素还回一直保存在内存中。如果该dom下有大量数据呢?而这个数据占用的内存将永远不会被释放。
标记-清除法:
这个算法假定设置了一个叫做“根”的对象(全局对象),定期的,垃圾回收器将从根出发,找所有从根开始引用的对象,然后找这个对象引用的对象......从根开始,垃圾回收器将找到所有可获得的对象和不可获得的对象
这个算法比上面的算法好。解决了循环引用的问题。
上面循环引用的例子,函数调用返回之后,两个对象从全局对象出发无法获取,因此他们将会被垃圾回收器回收。
从2012年起,所有现代浏览器都使用了标记-清除算法。所有对js垃圾回收的改进都是基于标记-清除算法的改进。其基础还是“对象是否可以获取”
缺点:
那些无法从根对象查询到的对象会被清除(这种情况,这种情况在开发中很少碰到)
网友评论