分享

理解IE的内存泄漏问题(1):重写 - Dixin's Blog - 博客园

 昵称574019 2010-03-18

最近不少同学提到IE的内存泄漏问题,这个问题实际上在MSDN上的文章《Understanding and Solving Internet Explorer Leak Patterns》里已经讲过了,但我并不赞同里面的很多说法。这里我希望通过一些例子和图片来演示一下这个现象。

首先是比较直观的一类现象:pseudo leak。比如,反复重写script对象的内部文本:

<script type="text/javascript">
    
function leak()
    {
        
for(i = 0; i < 300; i++)
        {
            document.getElementById(
"script").text = (new Array(100)).join((new Array(100)).join("function bigString(){};"));
        }
        alert(
"Complete!");
    }
</script>
<script id="script">function foo(){};</script>
<href="javascript:leak();">Start leak</a>

这样会造成泄漏,但刷新或跳转可以释放内存。下图是内存使用情况:

对此,MSDN上说:“You expect that after rewriting some script that the original script won't stay around. But it really has to, because it might have been used already for event attachments and there might be outstanding reference counts. As you can see, this is a pseudo-leak. On the surface the amount of memory consumption looks really bad, but there is a completely valid reason.”感觉比较荒唐。

不仅仅是重写script对象存在问题,甚至重复创建局部变量也会有pseudo leak问题:

<script type="text/javascript">
    
function leak()
    {
        
for(i = 0; i < 300; i++)
        {
            
var bigString = (new Array(1000)).join((new Array(1000)).join("big string"));
        }
        alert(
"Complete!");
    }
</script>
<href="javascript:leak();">Start leak</a>

有一点泄漏的迹象,但不严重,刷新或跳转之后恢复了正常:

比pseudo leak更严重的是actual leak。例如,用下面的方法反复创建的局部变量是一个DOM对象:

<script type="text/javascript">
    
function divClick(){}
    
function leak()
    {
        
for(i = 0; i < 50000; i++)
        {
            
var div = document.createElement("<div onclick='divClick();'></div>");//"<div onclick=''></div>" leads to the same result
        }
        alert(
"Complete!");
    }
</script>
<href="javascript:leak();">Start leak</a>

或者反复重写一个全局变量:

var div;
function divClick(){}
function leak()
{
    
for(i = 0; i < 50000; i++)
    {
        div 
= document.createElement("<div onclick='divClick();'></div>");//"<div onclick=''></div>" leads to the same result
    }
    alert(
"Complete!");
}

甚至只是创建,完全不存在重写:

for(i = 0; i < 500000; i++)
{
    document.createElement(
"<div onclick='divClick();'></div>");// "<div onclick=''></div>" leads to the same result
}

这三种情况都将导致显著的内存泄漏,而且刷新和跳转都不能解决问题。必须关闭IE:

这就不是pseudo leak了,而是actual leak。

网上一种广为流传的说法是“JavaScript中把变量设为null,JavaScript并不会把内存释放,当下次再次定义变量时,就会覆盖此变量所在的内存。如果不设为null,JavaScript再次定义变量时,会开辟一个新的内存空间。”但这也不对。比如将上面导致严重泄漏的代码变个样子:

function leak()
{
    
for(i = 0; i < 50000; i++)
    {
        
var div = document.createElement("div");
        div.onclick 
= function(){};
    }
    alert(
"Complete!");
}

这样就不会泄漏。重复定义变量div并没有开辟新的内存空间。

这个问题属于IE的缺陷,很难摸清规律,以后如果有新的发现,将会补充在这里。

本文中代码的测试结果:

  • IE 6:存在此问题,调用CollectGarbage()不能回收;
  • IE 7:和IE 6相同;
  • Firefox 2.0.0.8:正常(不支持document.createElement("<div onclick='divClick();'></div>"),只支持document.createElement("div"));
  • Opera 9.24:和Firefox相同;
  • Safari 3.0.3:和Firefox相同。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多