内存泄漏的实例:
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.event;
if(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);