JS内存泄露

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS内存泄露相关的知识,希望对你有一定的参考价值。

参考技术A 当内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。Chrome限制了浏览器所能使用的内存极限,64位为1.4GB,32位为1.0GB。

1.意外的全局变量
.未声明变量
.使用this创建的变量(this指向window)
解决办法:
.避免创建全局变量
.使用严格模式,在js文件头部或者函数的顶部加上use strict
2.闭包引起的内存泄露
原因:闭包可以读取函数内部的变量,然后让这些变量是始终保存在内存中。如果在使用结束后没有将局部变量清除,就可能导致内存泄露。
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中。
3.没有清除的DOM元素引用
原因:虽然别的地方删除了,但是对象中还存在对DOM的引用。
解决办法:手动删除,赋值为null
4.被遗忘的定时器或者回调
解决办法:手动删除定时器和DOM,removeEventListener移除事件监听

Js内存泄漏的几种情况

想解决内存泄露问题,必须知道什么是内存泄露,什么情况下出现内存泄露,才能在遇到问题时,逐个排除。这里只讨论那些不经意间的内存泄露。

一、什么是内存泄露

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

二、内存泄露的几种情况

1、当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在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>
技术分享


2、

var a=document.getElementById("xx");
var b=document.getElementById("xxx");
a.r=b;
b.r=a;

 

var a=document.getElementById("xx");
a.r=a;

 

对于纯粹的 ECMAScript 对象而言,只要没有其他对象引用对象 a、b,也就是说它们只是相互之间的引用,那么仍然会被垃圾收集系统识别并处理。但是,在 Internet Explorer 中,如果循环引用中的任何对象是 DOM 节点或者 ActiveX 对象,垃圾收集系统则不会发现它们之间的循环关系与系统中的其他对象是隔离的并释放它们。最终它们将被保留在内存中,直到浏览器关闭。

 

3、
技术分享
    
function bindEvent() 
{ 
    var obj=document.createElement("XXX"); 
    obj.onclick=function(){ 
        //Even if it‘s a empty function 
    } 
}
技术分享

 

闭包可以维持函数内局部变量,使其得不到释放。
上例定义事件回调时,由于是函数内定义函数,并且内部函数--事件回调的引用外暴了,形成了闭包
解决之道,将事件处理函数定义在外部,解除闭包
技术分享
function bindEvent() 
{ 
    var obj=document.createElement("XXX"); 
    obj.onclick=onclickHandler; 
} 
function onclickHandler(){ 
    //do something 
}
技术分享

 

或者在定义事件处理函数的外部函数中,删除对dom的引用(题外,《JavaScript权威指南》中介绍过,闭包中,作用域中没用的属性可以删除,以减少内存消耗。)

技术分享
    
function bindEvent() 
{ 
    var obj=document.createElement("XXX"); 
    obj.onclick=function(){ 
        //Even if it‘s a empty function 
    } 
    obj=null; 
}
技术分享

 

4、

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

 执行这段代码之后b.x的值依然是1.由于已经删除的属性引用依然存在,因此在JavaScript的某些实现中,可能因为这种不严谨的代码而造成内存泄露。所以在销毁对象的时候,要遍历属性中属性,依次删除。

5. 自动类型装箱转换

看网上资料,说下面的代码在ie系列中会导致内存泄露,先提个神,具体泄露与否先不管

var s=”lalala”;

alert(s.length);

 

s本身是一个string而非object,它没有length属性,所以当访问length时,JS引擎会自动创建一个临时String对象封装s,而这个对象一定会泄露。这个bug匪夷所思,所幸解决起来相当容易,记得所有值类型做.运算之前先显式转换一下:

var s="lalala";

alert(new String(s).length);




以上是关于JS内存泄露的主要内容,如果未能解决你的问题,请参考以下文章

JS中由闭包引发内存泄露的深思

opencv内存泄露问题

Js内存泄漏的几种情况

js中的内存泄漏

js的内存泄露

PHP CURL内存泄露的解决方法