什么是JavaScript内存泄漏与解决方法

内存泄漏的实例:

function getId() {
var div = document.getElementById("div1");
div.onclick = function() {
alert(div.id);
}
}

以上代码创建了一个作为div事件处理程序的闭包,而这个闭包又创建了一个循环引用。由于匿名函数保存了一个对getId()的活动对象的引用,因此会导致无法减少div的引用数。只要匿名函数存在,div的引用次数至少为1,它所占用的内存永远不会被回收。

 

解决方法:

function getId() {
var div = document.getElementById("div1");
var id = div.id;
div.onclick = function() {
alert(id);
}
div = null;
}

以上代码通过把div.id的一个副本保存在一个变量中,并且在闭包中引用该变量消除了循环引用。但仅仅做到这一步,还不能解决内存泄漏的问题,因为闭包会引用包含函数的整个活动对象,而其中包含着div,即使闭包不直接引用div,包含函数的活动对象中也仍然会保存一个引用。因此,有必要把div变量设为null。这样能够解除对DOM对象的引用,顺利地减少其引用数,确保正常的对其内存进行回收。

 

内存泄漏的几种情况:

1、当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,导致内存泄露。 

var btn = document.getElementById("btn"); 
btn.onclick = function(){ 
......
} 

 

解决方法:

① 手动移除元素绑定的事件

var btn = document.getElementById("btn"); 
btn.onclick = function(){ 
btn.onclick = null; 
......
} 

 

② 采用事件委托

document.onclick = function(event){
event = event || window.eventif(event.target.id == "myBtn"){ 
......
}
} 

 

2、对于对象而言,只要没有其他对象引用对象a、b,即它们只是相互之间的引用,那么仍然会被垃圾收集系统识别并处理。但是,在 IE中,垃圾收集系统不会发现它们之间的循环引用关系而释放它们,最终它们将被保留在内存中,直到浏览器关闭,这导致了内存泄漏。

var a = document.getElementById("a"); 
var b = document.getElementById("b"); 
a.name = b; 
b.name = a; 

 

3、一个DOM结点的事件处理函数内引用了该DOM对象,会形成闭包,产生一个循环引用,DOM对象在闭包释放之前不会被释放;而闭包作为DOM对象的事件处理函数而存在,所以在DOM对象释放前闭包也不会释放,由于这个循环引用的存在,DOM对象和闭包都不会被释放,造成内存泄露。

var btn = document.getElementById(btn); 
btn.addEventListener('click', function() { 
alert('You clicked ' + btn.value); 
});

 

4、在删除属性时,由于已经删除的属性引用依然存在,会造成内存泄露。所以在销毁属性的时候,要遍历属性中属性,依次删除。 

a = {p: {x: 1}}; 
b = a.p; 
delete a.p; //b.x仍为1

 

5、在定义一个基本类型的变量时,它没有其对应的引用类型的属性,所以当访问该属性时,JS引擎会自动创建一个对应的临时对象封装该基本类型变量,这个自动类型装箱转换的对象在IE系列中会造成内存泄漏。

var s = "Hello"; 
alert(s.length); 

 

解决方法:

对基本类型变量做转换,通过new方法将其转换为对应的引用类型后再访问属性。

var s = "Hello"; 
alert(new String(s).length);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.duanlonglong.com/qdjy/443.html