js内存泄露的几种情况详细探讨_javascript技巧

内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。在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、

复制代码 代码如下:

var elem = document.getElementById('test');
elem.addEventListener('click', function() {
alert('You clicked ' + elem.tagName);
});

这段代码把一个匿名函数注册为一个DOM结点的click事件处理函数,函数内引用了一个DOM对象elem,就形成了闭包。这就会产生一个循环引用,即:DOM->闭包->DOM->闭包...DOM对象在闭包释放之前不会被释放;而闭包作为DOM对象的事件处理函数存在,所以在DOM对象释放前闭包不会释放,即使DOM对象在DOM tree中删除,由于这个循环引用的存在,DOM对象和闭包都不会被释放。可以用下面的方法可以避免这种内存泄露

复制代码 代码如下:

var elem = document.getElementById('test');
elem.addEventListener('click', function() {
alert('You clicked ' + this.tagName); // 不再直接引用elem变量
});

4、

复制代码 代码如下:

function bindEvent()
{
var obj=document.createElement("XXX");
obj.onclick=function(){
//Even if it's a empty function
}
}

闭包非常容易构成循环引用。如果一个构成闭包的函数对象被指定给,比如一个 DOM 节点的事件处理器,而对该节点的引用又被指定给函数对象作用域中的一个活动(或可变)对象,那么就存在一个循环引用。
DOM_Node.onevent -<function_object.[[scope]] -<scope_chain -<Activation_object.nodeRef -<DOM_Node。

形成这样一个循环引用是轻而易举的,而且稍微浏览一下包含类似循环引用代码的网站(通常会出现在网站的每个页面中),就会消耗大量(甚至全部)系统内存。
解决之道,将事件处理函数定义在外部,解除闭包

复制代码 代码如下:

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;
}

5、

复制代码 代码如下:

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

执行这段代码之后b.x的值依然是1.由于已经删除的属性引用依然存在,因此在JavaScript的某些实现中,可能因为这种不严谨的代码而造成内存泄露。所以在销毁对象的时候,要遍历属性中属性,依次删除。
6. 自动类型装箱转换
别不相信,下面的代码在ie系列中会导致内存泄露

复制代码 代码如下:

var s=”lalala”;
alert(s.length);

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

复制代码 代码如下:

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

7、某些DOM操作
IE系列的特有问题 简单的来说就是在向不在DOM树上的DOM元素appendChild;IE7中,貌似为了改善内存泄露,IE7采用了极端的解决方案:离开页面时回收所有DOM树上的元素,其它一概不管。

时间: 2025-01-26 18:15:20

js内存泄露的几种情况详细探讨_javascript技巧的相关文章

IE6已终止操作问题的2种情况及解决_javascript技巧

令人崩溃的IE6问题再次出现,打开某个页面时,弹出提示框"Internet Explorer无法打开Internet 站点...已终止操作". 查了一下资料,感觉"因为js(一个比较复杂的js)写在body里面,在body元素加载完之前调用出现问题"的说法比较靠谱. 经过一番奋战,利用排除法解决了问题,共发现2种情况. ①原因:同一JS文件,先后引入2次. 解决:删除一个即可. ②原因:在body里直接调用JS文件中的方法. 解决:通过onload或jquery.r

js优化针对IE6.0起作用(详细整理)_javascript技巧

js优化针对IE6.0起作用,总结一下几点: 一,字符串拼接:用数组拼接 复制代码 代码如下: function func2(){ var start = new Date().getTime(); var array = []; for(var i = 0; i < 10000; i++){ array[i] = "<input type='button' value='a'>"; } 二,for 循环:先把长度算出来直接调用 复制代码 代码如下: function

js字符串引用的两种方式(必看)_javascript技巧

如下所示: function setName(obj) { obj.ok = "ccccccc"; } function aa() { var name = new String("hechangmin"); name.ok = "sdf"; //第一种方式 // String.prototype.ok = "aaaaa"; //第二种方式 alert(name.ok); // aaaaa setName(name); ale

js变量作用域及可访问性的探讨_javascript技巧

每一种语言都有变量的概念,变量是用来存储信息的一个元素.比如下面这个函数:  复制代码 代码如下:  function Student(name,age,from)  {   this.name = name;    this.age = age;   this.from = from;    this.ToString = function()   {    return "my information is name: "+this.name+",age : "

js鼠标及对象坐标控制属性详细解析_javascript技巧

offsetTop获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算顶端位置. offsetLeft获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置. offsetHeight获取对象相对于版面或由父坐标 offsetParent 属性指定的父坐标的高度.IE.Opera 认为 offsetHeight = clientHeight + 滚动条 + 边框.NS.FF 认为 offsetHeight 是网页内容实际高度,可以小于 clientH

js中window.open()的所有参数详细解析_javascript技巧

[1.最基本的弹出窗口代码]  复制代码 代码如下:  <SCRIPT LANGUAGE="javascript">  <!--  window.open ('page.html')  -->  </SCRIPT>    因为着是一段javascripts代码,所以它们应该放在<SCRIPT LANGUAGE="javascript">标签和</script>之间.<!-- 和 -->是对一些版

js中创建对象的几种方式示例介绍_javascript技巧

JavaScript中的所有事物都是对象:字符串.数组.数值.函数等.JS中并没有类的概念, 但我们可以利用JS的语法特征,以类的思想来创建对象. 原始方法 复制代码 代码如下: <script type="text/javascript"> var obj = new Object(); obj.name = "Koji"; //为对象添加属性 obj.age = 21; obj.showName = function(){ //为对象添加方法 ale

js读取json的两种常用方法示例介绍_javascript技巧

方法一:js中最著名的eval方法 复制代码 代码如下: var strJson="{name:'张三'}";//json var obj=eval("("+strJson+")");//转换后的json对象 alert(obj.name);//json name 此方法需要注意的是: 对象表达式{'name':'张三'}必须用"()"扩住,否则 复制代码 代码如下: var strJSON = "{name:'张三

多个js与css文件的合并方法详细说明_javascript技巧

在Web项目的开发中,js,css文件会随着项目的开发变得越来越多,越来越大,这就给给性能方面带来一些问题,如,页面引入的的js,css越多的话,那么对就增加了http请求数,解决该问题的一个好的方法就是合并js,css文件. 下面就简单介绍一个方法,十分简单.下面介绍以合并js文件为例 (1) G.js文件 复制代码 代码如下: ~function(){ window.G={}; G.Method={ add:function(){ alert(111);} ,sub:function(){