JavaScript是一种具备垃圾回收机制的语言,所以开发人员无需过多担心内存泄漏问题。垃圾回收器会定期释放那些已经不需要再使用的变量占有的内存。
主要的垃圾回收算法有标记法和引用计数法。
标记法:当进入某个执行环境的时候,这个环境中的所有变量对象都被标记为可用,垃圾回收机制就永远不会释放它们的内存。当这个执行环境结束的时候,其中的所有变量对象就被标识为不可用,当垃圾回收器发现这些被标记为不再可用的变量对象时,就释放它们的内存。当然这只是个概念,具体的实现方法因浏览器不同而异。
引用计数法:当某个对象或者值被某个变量引用的时候,这个对象或值的引用计数就加1,被多个变量引用就多次加1。如果当引用这个对象或值的某个变量引用另一个对象去了,那么这个对象或值的引用计数就减1,以此类推,当引用计数减到0的时候,就意味着程序不需要再使用它了,垃圾回收器就会释放它的内存。
例子:
var a = new Object(); // 对象被a变量引用,引用计数是1
var b = a; // 对象再次被b变量引用,引用计数就变成2
b = 123; // b开始引用数字123,于是对象的引用计数又变成了1
引用计数法存在一个严重的问题就是当存在循环引用的时候,垃圾回收机制永远不能回收被引用的对象的内存,就造成了内存泄漏。
例子:
function fun()
{
var a = new Object(); // 我们叫它对象1
var b = new Object(); // 我们叫他对象2
a.myObject = b; // a的某个属性引用了b,对象2的引用计数是2
b.myObject = a; // b的某个属性引用了a,对象1的引用计数是2
} // 当fun的执行环境结束的时候,a与b作为局部变量被自动销毁,此时对象1和对象2的引用计数变为1,但是永远不会被垃圾回收器回收
大多数浏览器都采用标识法,而IE中的BOM和DOM对象是采用COM实现的,COM对象的垃圾回收机制就是采用引用计数法。所以在IE中为了避免发生内存泄漏,我们通常需要手动消除引用,比如我们将a.myObject = null就可以消除引用了。
我们进行手动的消除引用,不仅仅是为了避免内存泄漏,这同样也是一个很好的编程习惯。因为计算机分配给浏览器的内存大小大比桌面软件要少,所以我们需要节约使用内存,从而让页面达到最佳的性能。对于局部变量,我们不需要手动释放它,但是对于全局的变量,一旦确定不再使用它,我们就将其设置为null就可以搞定了。