JavaScript内存泄露及解决方案详解

一、什么是内存泄露

内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。在C++中,因为是手动管理内存,内存泄露是经常出现的事情。而现在流行的C#和Java等语言采用了自动垃圾回收方法管理内存,正常使用的情况下几乎不会发生内存泄露。浏览器中也是采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,会产生内存泄露。

二、引起垃圾收集语言内存泄露的主要原因是不必要的引用。

三、内存泄露的几种情况

1.意外的全局变量

体现 JavaScript 宽容性的一点表现在它处理未声明变量的方式上:一个未声明变量的引用会在全局对象中创建一个新的变量。在浏览器的环境下,全局对象就是 window,也就是说:

functionfoo(arg){

bar="this is a hidden global variable";

}

实际上是:

functionfoo(arg){

window.bar="this is an explicit global variable";

}

如果 bar 是一个应该指向 foo 函数作用域内变量的引用,但是你忘记使用 var 来声明这个变量,这时一个全局变量就会被创建出来。在这个例子中,一个简单的字符串泄露并不会造成很大的危害,但这无疑是错误的。

2.闭包
function bindEvent() 
{ 
    var obj=document.createElement("XXX"); 
    obj.οnclick=function(){ 
        //Even if it's a empty function 
    } 
}
闭包可以维持函数内局部变量,使其得不到释放。
上例定义事件回调时,由于是函数内定义函数,并且内部函数--事件回调的引用外暴了,形成了闭包
解决之道,将事件处理函数定义在外部,解除闭包
function bindEvent() 
{ 
    var obj=document.createElement("XXX"); 
    obj.οnclick=onclickHandler; 
} 
function onclickHandler(){ 
    //do something 
}
或者在定义事件处理函数的外部函数中,删除对dom的引用
function bindEvent() 
{ 
    var obj=document.createElement("XXX"); 
    obj.οnclick=function(){ 
        //Even if it's a empty function 
    } 
    obj=null; 
}

3.没有清理的DOM元素的引用

即当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,此时要先手工移除事件,不然会存在内存泄露。

复制代码
<div id="myDiv">
    <input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
    var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        document.getElementById("myDiv").innerHTML = "Processing...";
    }
</script>
复制代码

应改成下面

复制代码
<div id="myDiv">
    <input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
    var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        btn.onclick = null;
        document.getElementById("myDiv").innerHTML = "Processing...";
    }
</script>
复制代码

或者采用事件委托

复制代码
<div id="myDiv">
    <input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
    document.onclick = function(event){
        event = event || window.event;
        if(event.target.id == "myBtn"){
            document.getElementById("myDiv").innerHTML = "Processing...";
        }
    }
</script>
4. 被遗忘的定时器或者回调
<script type="text/javascript">
	var someResource = getData(){
		setInterval(function(){
			var node = document.getElementById('Node');
			if (node)
			{
				node.innerHTML = JSON.stringify(someResource);
			}
		},1000);
	}
  </script>
5.自动类型装箱转换(IE6,IE7)
var s="hhhhh";
alert(s.length);
"hhhhh"已经泄露了,关键问题出在s.length上,在js类型中,String类型并非对象,但是可以可以使用(.)运算符,因为js的默认类型转换机制,允许js在遇到(.)运算符时,自动将string类型转换为Object中对应的String对象。该临时转换的对象100%会泄露。
应改为
var s="lalala";
alert(new String(s).length);

扩展:
一.如何避免内存泄漏

1.减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收

2.注意程序逻辑,避免死循环之类的

3.避免创建过多的对象

原则:不用了的东西要及时归还。

二.内存泄露的一些疑问

1、内存泄露是内存占用很大吗?
不是,即使是1byte的内存,也叫内存泄露。
2、程序中提示内存不足,是内存泄露吗?
 不是,着一般是无限递归函数调用,导致栈内存溢出。
3.内存泄露是哪个区域?
  堆区。栈区不会泄露
4.window对象时DOM对象吗?
不是,window对象参与的循环引用是不会内存泄露。
5.内存泄露的后果?
大多数情况下,后果不是很严重。但是过多的DOM操作会使网页执行速度变慢。
6.跳转网页,内存泄露仍然存在吗?
仍然存在,直到浏览器关闭。










已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页