您的位置:首页 > Web前端 > JavaScript

JavaScript的垃圾收集

2016-06-30 22:25 295 查看
原文地址:点击打开链接

垃圾回收(garbage collection):在JavaScript中具有自动垃圾收集机制,其工作原理就是找出那些不再继续使用的变量,释放其占用的内存。垃圾收集器会在固定的时间间隔周期性的执行这一操作。

首先说一下函数中局部变量的正常声明周期。局部变量只在函数执行过程中存在。而在这个过程中,会为局部变量在栈(或堆)内存上分配相应的空间,来存储他们。然后在函数中使用这些变量,直至函数执行结束。此时,函数内部的函数或者变量在内存中就失去了意义。因此可以释放他们。由此,需要判断变量是否还有存在的必要。垃圾收集器需要设计成能够跟踪哪个变量有用哪个没用,对于不再有用的变量打上标记,以备将来收回。在浏览器中实现用于标识无用变量的策略通常有两个:

1.标记清除(mark-and-sweep):此策略比较常用。

当变量进入环境时,就将这个变量标记为“进入环境",而当变量离开环境后,将其标记为”离开环境“。垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记,然后它会去掉环境中的变量以及被环境中的变量引用的变量的标记。在此之后,再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量无法访问到这些变量。最后垃圾收集器会完成内存清除,销毁带有标记的值并且回收它们所占的内存。

2.引用计数(reference
counting) :此策略不太常见。

就是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋给该变量时,这个值得引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1,相反,如果包含对这个值引用的变量又取得了另外一个值,这个值得引用次数减1,当这个值得引用次数为0时,说明无法再访问该值,此时就可以将其占有的内存回收回来。这样,当垃圾收集器再次运行时,就会释放这些引用次数为0所占用的内存。(此处需要认真理解,我做了下面一个例子来阐述这一点)

1.// 下面定义一个变量p引用着内存中的一个对象,我们把这个对象叫做对象foo,对象foo当前的引用计数为1  
2.var p = {"name":"foo","age":12};   
3.// 我们再次定义一个变量t,用t来保存对象foo,因为p指向对象foo,所以下面的操作,对象foo的引用计数为2  
4.var t = p;  
5.// 我们再次进行操作,让t去保存其他的值,这样对象foo的引用计数变成了1,此时只有变量p引用着对象foo  
6.t = 1;  
7.// 我们再次操作,给变量p重新赋值,那么内存中的对象foo,就没有任何变量引用了,因此对象foo的引用计数为0  
8.p = 2;  
9.// 因为在内存中的对象foo,我们无法通过任何的形式去访问,因此对象foo成为了垃圾内存,等待着被回收。  

但是引用计数策略也带来了一些问题,就是循环引用。循环引用:对象A包含一个对象B的指针,对象B包含一个指向对象A的引用。当函数执行完毕后对象A和对象B的引用计数永远不会是0,因此无法回收,如果同一个函数多次调用,就会有大量内存变成了无法回收的垃圾内存,就会导致内存泄漏。下面是这个问题的例子:

1.function problem() {  
2.  var A = new Object();  
3.  var B = new Object();  
4.  A.someAttr = B;  
5.  B.anotherAttr = A;  
6.}  


为什么IE8,及其以下浏览器的性能不是很好,下面来做一番解释:在这些版本浏览器中的一部分对象不是原生JS对象,例如:其BOM和DOM中的对象就是使用C++以COM(Component Object Model,组件对象模型)对象的形式来实现的。而COM对象的垃圾回收机制就是引用计数。换句话说只要IE中涉及COM对象,就会存在循环引用的问题。不过IE9把BOM和DOM转换成了真正的js对象。这样就避免了那些问题,也消除了内存泄漏的现象。

在上述例子中,为避免在ie8及其以下浏览器版本的问题,最好在不适用他们的时候手动断开原生js对象和DOM对象之间的连接,手动把他们置为null
1.A.someAttr = null;  
B.anotherAttr = null;


但是问题来了,我怎样去手动置空呢,在problem函数之外是无法实现的,必须在函数内部实现,但是直接实现又不可取,那么需要在函数外面定义一个哨兵变量,用来标识在什么条件下去置空,当然标识的条件可以多种多样,代码可以这样实现,做一个假想的例子:

1.var count = 0;  
2.function problem(count) {  
3.  var A = new Object();  
4.  var B = new Object();  
5.  count ++;  
6.  if(count>=5) {  
7.    A.someAttr = null;  
8.    B.anotherAttr = null;  
9.    return;  
10.  }  
11.  A.someAttr = B;  
12.  B.anotherAttr = A;  
13.}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript 垃圾收集