JavaScript内存泄漏原理与IE环境下的解决方案

作者:代码拾荒时间:2026-10-28 16:13:38浏览:533

本文详解JavaScript自动垃圾回收机制及内存泄漏成因,重点分析循环引用与闭包导致的内存无法释放问题。针对IE浏览器中DOM节点与JS对象循环引用引发的特殊泄漏,提供了手动切断引用及遍历清除事件处理器的具体代码方案。

JavaScript内存泄漏原理与IE环境下的解决方案

关于闭包及其涉及的作用域链概念,此处不再赘述。

JavaScript垃圾回收机制

JavaScript垃圾回收机制

JavaScript采用自动垃圾回收机制(garbage collection),无需手动释放内存。当程序中没有任何变量引用某个对象时,该对象即被视为无用,系统会自动从内存中将其释放。

代码如下:

var s = [ 1, 2 ,3];
var s = null;
执行上述操作后,原始数组[1 ,2 ,3]所占用的内存将被释放。

循环引用分析

循环引用

考虑三个对象 A 、B 、C

AàBàC :若A的某个属性引用B,且B的属性引用C,当A被清除时,B和C也会随之被释放。

AàBàCàB :若C的某个属性再次引用B,形成闭环。此时若仅清除A,由于B和C之间存在循环引用,两者均无法被释放。

代码如下:

var a = {};
a.pro = { a:100 };
a.pro.pro = { b:100 };
a = null ;
在此情况下,{a:100}和{b:100}对象均会被正常释放。
            
var obj = {};
obj.pro = { a : 100 };
obj.pro.pro = { b : 200 };
var two = obj.pro.pro;
obj = null;
在此情况下,{b:200}对象因被变量two引用而不会被释放,而{a:100}对象则被释放。
 

循环引用和闭包

循环引用和闭包

代码如下:

function outer(){
var obj = {};
function inner(){
//这里引用了obj对象
        }
obj.inner = inner;
    }

这是一种极其隐蔽的循环引用。当调用一次outer时,会在其内部创建obj和inner两个对象。obj的inner属性引用了inner函数;同时,inner函数通过作用域链引用了外部变量obj。这种由JavaScript特有的“作用域链”导致的循环引用非常常见,幸运的是JavaScript引擎通常能较好地处理此类情况。

IE中的内存泄漏

IE中的内存泄漏

IE浏览器中存在多种内存泄漏情况,详细解释可参考(http://msdn.microsoft.com/en-us/library/bb250448.aspx)。

此处仅讨论由循环引用造成的一种最普遍的情况。

当DOM元素或ActiveX对象与普通JavaScript对象之间存在循环引用时,IE在释放这类变量时会遇到特殊困难。建议在IE 7之前手动切断循环引用,该bug在IE 7中已得到修复(http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html)。

“IE 6 suffered from memory leaks when a circular reference between several objects, among which at least one DOM node, was created. This problem has been solved in IE 7. ”

若上述例子(第4点)中obj引用的不是JavaScript Function对象(inner),而是ActiveX对象或Dom元素,则在IE中形成的循环引用将无法得到释放。

代码如下:

function init(){
var elem = document.getElementByid( 'id' );
elem.onclick = function(){
alert('rain-man');
//这里引用了elem元素
        };
    }

elem元素引用了其click事件的监听函数,而该函数通过作用域链又引用回elem元素。这种循环引用导致在IE中即使离开当前页面,相关内存也不会被释放。

解决方法

解决方法

基本方法是手动清除循环引用。以下是一个简单示例,实际应用中可自行构建addEvent()函数,并在window的unload事件上对所有事件绑定进行清除。

代码如下:

function outer(){
var one = document.getElementById( 'one' );
one.onclick = function(){};
    }
window.onunload = function(){
var one = document.getElementById( 'one' );
one.onclick = null;
    };

其它方法(by:Douglas Crockford)

代码如下:

/**
* 遍历某一元素节点及其所有后代元素
 *
* @param Elem node 所要清除的元素节点
* @param function func 进行处理的函数
 * 
 */
function walkTheDOM(node, func) {
func(node);
node = node.firstChild;
while (node) {
walkTheDOM(node, func);
node = node.nextSibling;
    } 
} 
/**
* 清除dom节点的所有引用,防止内存泄露
 *
* @param Elem node 所要清除的元素节点
 * 
 */
function purgeEventHandlers(node) {
walkTheDOM(node, function (e) {
for (var n in e) {
if (typeof e[n] ===
'function') {
e[n] = null;
            }
        }
    });

以上即为JavaScript内存泄漏的相关内容以及解决方案,有需要的小伙伴可以参考下

作者最新文章