Skip to content

内存管理机制 ​

本节目标:理解“内存管理机制”的核心思路,并能把它用于实际开发或面试表达。

**标记清除****(mark-and-sweep)**

引用计数**(reference counting)** 当声明一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾收集器下次再运行时,它就会释放那些引用次数为零的值所占用的内存。

引用计数策略有一个严重的问题:循环引用
它指的是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用。
function problem() {
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
objectB.antherObject = objectA;
}

objectA和objectB通过各自的属性相互引用;这两个对象的引用次数都是2。在采用标记清除策略的实现中,由于函数执行之后,这两个对象都离开了作用域,因此这种相互引用不是个问题。但在采用引用计数策略的实现中,当函数执行完毕后,objectA和objectB还将继续存在,因为它们的引用次数永远不会是0。假如这个函数被重复多次调用,就会导致大量内存得不到回收。

IE中有一部分对象并不是原生JavaScript对象。例如,其BOM和DOM中的对象就是使用C++以COM(Component Object Model,组件对象模型)对象的形式实现的,而COM对象的垃圾收集采用的就是引用计数策略。所以,只要在IE中涉及COM对象,就会存在循环引用的问题。如下例:
var element = document.getElementById("some_element");
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;
由于存在循环引用,即使将例子中的DOM从页面中移除,它也永远不会被回收。
为了避免类似这样的循环引用问题,最好是在不使用它们的时候手工断开原生JavaScript对象与DOM元素之间的连接。例如,可以这样
myObject.element = null;
element.someObject =null;
将变量设置为null意味着切断变量与它此前引用的值之间的连接。

IE9把BOM和DOM对象都转换成了真正的JavaScript对象。 导致循环引用的情况不止这些。

解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。

本站总访问 — 次