首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 挑战超难问题,寻高手帮助解决 一个典型的 半透明层 内存泄露问题 [已结贴,结贴人:DBXP]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 09:13:52 楼主
    挑战超难问题,寻高手帮助解决 一个典型的 半透明层 内存泄露问题
    问题描述:javascript动态添加一个半透明的DIV标签和一个关闭按钮,点击关闭按钮后内存无法释放,反复几次内存无限制上涨。

    具体测试:(必须在IE下测试才能发现问题)
    1、依次执行“添加”“删除”“释放内存”,如此反复多次,发现内存可以正常释放。
    2、依次执行“添加”“从内部删除”“释放内存”,如此反复多次,发现内存泄露无限制增长。


    源代码如下:
    HTML code
    <html> <head> <script language="javascript"> var arr = new Array(); function c() { var div = document.createElement("DIV"); document.body.appendChild(div); div.innerHTML = '<input type="button" value="从内部删除" onclick="f()"/><div style="position:absolute;top:110;left:110;width:1000px;height:1000px;-moz-opacity:0.07;filter:alpha(opacity=7);background-color:#000000"></div>'; arr.push(div); abcd.innerText = arr.length; } function f() { var tmp = arr.pop(); while(tmp!=null) { // for(var i = tmp.childNodes.count-1; i >=0 ; i--) // { // tmp.removeChild(tmp.childNodes[i]); // } document.body.removeChild(tmp); tmp = arr.pop(); } abcd.innerText = arr.length; } function g() { CollectGarbage(); } </script> </head> <body> <input type="button" value="添加" onclick="c();" /> <input type="button" value="删除" onclick="f();" /> <input onclick="g()" type="button" value="释放内存" /> <div id="abcd"></div> 典型的 半透明层 内存泄露问题:<br /> 测试:(必须在IE下测试才能发现问题)<br /> 1、依次执行“添加”“删除”“释放内存”,如此反复多次,发现内存可以正常释放。<br /> 2、依次执行“添加”“从内部删除”“释放内存”,如此反复多次,发现内存泄露无限制增长。 </body> </html>

    100  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-09 09:33:261楼 得分:5
    HTML code
    <html> <head> <script language="javascript"> var arr = new Array(); function c() { var div = document.createElement("DIV"); document.body.appendChild(div); div.innerHTML = '<input type="button" value="从内部删除" onclick="f()"/><div style="position:absolute;top:110;left:110;width:1000px;height:1000px;-moz-opacity:0.07;filter:alpha(opacity=7);background-color:#000000"></div>'; arr.push(div); abcd.innerText = arr.length; } function f() { var tmp = arr.pop(); while(tmp!=null) { document.body.removeChild(tmp); tmp.childNodes[1].style.filter = "";//发现style的filter是个特殊的东西 需要手动释放一下 tmp = arr.pop(); } abcd.innerText = arr.length; this.onclick = null; } function g() { CollectGarbage(); } </script> </head> <body> <input type="button" value="添加" onclick="c();" /> <input type="button" value="删除" onclick="f();" /> <input onclick="g()" type="button" value="释放内存" /> <div id="abcd"></div> 典型的 半透明层 内存泄露问题:<br /> 测试:(必须在IE下测试才能发现问题)<br /> 1、依次执行“添加”“删除”“释放内存”,如此反复多次,发现内存可以正常释放。<br /> 2、依次执行“添加”“从内部删除”“释放内存”,如此反复多次,发现内存泄露无限制增长。 </body> </html>
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • llddy
    • 等级:
    发表于:2007-11-09 09:38:032楼 得分:1
    帮顶一下。。

    我解决不了
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-09 09:54:163楼 得分:5
    方法1:
    对于remove的对象来说,它还是存在的,可以append回来:

    <html>
    <head>
    <script language="javascript">
    var arr = new Array();
    var currentNum=0;
    function c()
    {
    if(arr[currentNum]) document.body.appendChild(arr[currentNum]);
    else{
         var div = document.createElement("DIV");
         document.body.appendChild(div);
         div.innerHTML = ' <input type="button" value="从内部删除" onclick="f()"/> <div style="position:absolute;top:110;left:110;width:1000px;height:1000px;-moz-opacity:0.07;filter:alpha(opacity=7);background-color:#000000"> </div>';
         arr.push(div);
        }
        currentNum++;
        abcd.innerText = currentNum;
    }

    function f()
    {
        for (var i=currentNum-1;i>-1;i--)
        {
            document.body.removeChild(arr[i]);
        }
        currentNum=0;
        abcd.innerText = currentNum;
    }

    function g()
    {
        CollectGarbage();
    }

    </script>
    </head>
    <body>

    <input type="button" value="添加" onclick="c();" />
    <input type="button" value="删除" onclick="f();" />
    <input onclick="g()" type="button" value="释放内存" />
    <div id="abcd"> </div>
    典型的 半透明层 内存泄露问题: <br />
    测试:(必须在IE下测试才能发现问题) <br />
    1、依次执行“添加”“删除”“释放内存”,如此反复多次,发现内存可以正常释放。 <br />
    2、依次执行“添加”“从内部删除”“释放内存”,如此反复多次,发现内存泄露无限制增长。
    </body>
    </html>
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • btbtd
    • 等级:
    发表于:2007-11-09 09:54:244楼 得分:0
    if(fCkBrs()===1)onunload = function(){fFixMl();};


      function fFixMl(oEle)
      { // shawl.qiu code, void return
       if(!oEle)oEle=document.body;
       var atr=oEle.attributes;
       if(atr)
        for(var i=0, j=atr.length; i <j; i++)
         if(typeof oEle[atr[i].name]=='function')oEle[atr[i].name]=null;
       if(oEle.childNodes)
        for(var i=0, j=oEle.childNodes.length; i <j; i++)
         arguments.callee(oEle.childNodes[i]);
      } // end function fFixMl(oEle)


      function fCkBrs()
      {// shawl.qiu script, return integer
       switch (navigator.appName)
       {
        case 'Opera': return 2;
        case 'Netscape': return 3;
        default: return 1;
       }
      } // end function fCkBrs 
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 09:58:335楼 得分:0
    我是楼主:

    经过几天的调试分析,初步得出一种猜测,仅供大家参考,只是猜测,千万别被我误导:
    点击“从内部删除”按钮的时候,所以造成了资源相互引用,所以CollectGarbage()认为资源仍然被占用,所以不去释放资源。


    备注:因为是在IE上发现的这个问题,火狐下没有发现类似情况,所以我准备给微软写信,大家支持我一下,有了新的进展我会及时贴到这个帖子后面。希望大家继续讨论问题。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-09 09:58:546楼 得分:5
    也可以用innerHTML删除:

    <html>
    <head>
    <script language="javascript">
    var currentNum=0;
    function c()
    {
        var div = document.createElement("DIV");
        document.getElementById("aaaaa").appendChild(div);
        div.innerHTML = ' <input type="button" value="从内部删除" onclick="f()"/> <div style="position:absolute;top:110;left:110;width:1000px;height:1000px;-moz-opacity:0.07;filter:alpha(opacity=7);background-color:#000000"> </div>';
        currentNum++;
        abcd.innerText = currentNum;
    }

    function f()
    {
        document.getElementById("aaaaa").innerHTML="";
        currentNum=0;
        abcd.innerText = currentNum;
    }

    function g()
    {
        CollectGarbage();
    }

    </script>
    </head>
    <body>

    <input type="button" value="添加" onclick="c();" />
    <input type="button" value="删除" onclick="f();" />
    <input onclick="g()" type="button" value="释放内存" />
    <div id="abcd"> </div>
    典型的 半透明层 内存泄露问题: <br />
    测试:(必须在IE下测试才能发现问题) <br />
    1、依次执行“添加”“删除”“释放内存”,如此反复多次,发现内存可以正常释放。 <br />
    2、依次执行“添加”“从内部删除”“释放内存”,如此反复多次,发现内存泄露无限制增长。
    <div id="aaaaa">
    </div>
    </body>
    </html>
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-09 10:00:167楼 得分:5
    我又测试了一下发现还是onclick事件的问题 
    只要在卸载将onclick事件置空就可以完全释放内存了
    我测试添加20次 删除 再添加20次 内存都是98M左右 而且不用使用CollectGarbage()方法

    JScript code
    function f() { var tmp = arr.pop(); while(tmp!=null) { document.body.removeChild(tmp); tmp.onclick = null;//onclick事件也最好置空一下 tmp = arr.pop(); } abcd.innerText = arr.length; }

    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • btbtd
    • 等级:
    发表于:2007-11-09 10:01:058楼 得分:1
    都是一些事件搞的, 这问题你不用给MS写信了, N早有N多人知道了...
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-09 10:01:579楼 得分:1
    另外你可以去看看我以前的帖子
    http://topic.csdn.net/u/20070501/09/eeb7bb7b-ebe9-432d-a496-87a645e75cfd.html
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-09 10:03:3410楼 得分:1
    我在傲游下都正常。。。。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 10:06:3811楼 得分:0
    回复1楼:(gzdiablo)
    我把你贴的代码原样测试了一下,发现问题依旧。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 10:15:2012楼 得分:0
    回复3楼(JK_10000)
    removeChild 之后我又调用了 CollectGarbage(); 所以内存应该得到释放了,因为点击“删除”按钮(参考测试1)后就可以正常释放内存。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 10:25:0613楼 得分:0
    回复4楼(btbtd )
    不好意思,小弟才疏学浅,没看明白兄弟写的什么意思。麻烦哪位朋友给讲解一下
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 10:37:5714楼 得分:0
    回复6楼(JK_10000)
    和你之前描述的情况一样,我测试了一下,只要与arr脱离了关系又removeChild了,应该可以正常释放了,因为没有了任何引用,即使这个内存不释放也不能再次使用了,所以调用CollectGarbage(); 应该正常释放的。

    另外,参考我之前说过的理由:
    removeChild   之后我又调用了   CollectGarbage();   所以内存应该得到释放了,因为点击“删除”按钮(参考测试1)后就可以正常释放内存。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • muxrwc
    • 等级:
    发表于:2007-11-09 10:42:0015楼 得分:1
    月の影 11:45:30
    js和DOM对象占用的内存很多
    IE下createElement的DOM对象无论如何应当挂到documentElement之下的节点中去
    否内进程里的内存白丢
    别指望被回收

    月の影 12:07:11
    所以最好不要临时生成 不用的DOM对象

    月の影 12:07:48
    我不知道为什么,只能理解为
    对于进程来说DOM对象申请的资源是永久的
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • muxrwc
    • 等级:
    发表于:2007-11-09 10:43:1716楼 得分:1
    IE下createElement的DOM对象无论如何应当挂到documentElement之下的节点中去 
    否内进程里的内存白丢 
    别指望被回收 


    即使挂上去了,也不会被回收。。。只是不挂,心理不平衡:D
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 10:43:2817楼 得分:0
    回复第7楼(gzdiablo):
    按照你所讲的,设置了tmp.onclick = null;
    我测试了,结果问题仍然没有改变。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-09 10:48:4618楼 得分:1
    To:   DBXP  
    ----
    楼主的出发点:确认这是个IE的bug,可以向IE报告。
    JK的出发点:碰到IE的bug,只能当作是踩到了便便,绕过就成。---另:给IE报bug的古道热肠值得鼓励.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 10:56:2819楼 得分:0
    补充:回复第7楼(gzdiablo): 
    连续点开20个层然后一起关闭,最后释放内存,这样确实可以释放一些内存,但是反复几次发现内存会持续上涨。
    如果你打开一个关闭一个立即释放内存,反复重复上述过程,就会发现内存几乎没有一点释放的
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 11:00:4220楼 得分:0
    给大家个提醒:
    大家测试的时候,观察windows 任务管理器的 “PF使用”,而不是“进程”选项卡。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 11:05:2521楼 得分:0
    回18楼:JK_10000
    问题是没有办法绕过啊,想了N多办法,如果可以绕过,早就绕了,谁也不愿意死抓着不放手。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-09 11:17:3822楼 得分:10
    IE 会释放的 但不是立刻 可能要等一会 
    加20个层时内存测试

    开始PF:806MB
    第一次 98.224k
    第二次 98.444k
    3: 98.544k
    4: 98.676k
    5: 98.680k
    6: 98.752k
    7: 98.748k
    8: 98.752k
    9: 98.628k
    10: 98.752k
    11: 98.756k
    12: 98.752k
    13: 98.748k
    14: 98.684k
    15: 98.764k
    16: 98.768k
    17: 98.784k
    18: 98.768k
    19: 98.716k
    20: 98.716k

    20次之后PF:807MB
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 11:27:5923楼 得分:0
    回22楼:gzdiablo
    你的怎么涨的这么慢?我的每添加一个层PF就增加4M
    我使用的是IE6
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • DBXP
    • 等级:
    发表于:2007-11-09 11:33:3024楼 得分:0
    回复4楼:btbtd
    我看明白你的代码了,增加你的代码后,内存依然没有被释放掉
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • muxrwc
    • 等级:
    发表于:2007-11-09 12:05:0925楼 得分:1
    经JK前辈指点。。。


    JScript code
    <script type="text/javascript"> var arr = []; function c() { document.body.innerHTML += '<div id="tdiv_'+ arr.length + '">' + '<div style="position:absolute;top:110;left:110;width:1000px;height:1000px;-moz-opacity:0.07;filter:alpha(opacity=7);background-color:#000000"></div>' + '</div>'; arr[arr.length] = "tdiv_" + arr.length; } function f() { while(tmp = arr.pop()) { tmp = document.getElementById(tmp); if (tmp.outerHTML) tmp.outerHTML = ""; else tmp.parentNode.removeChild(tmp); } } </script> <input type="button" value="添加" onclick="c();" /> <input type="button" value="删除" onclick="f();" />
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-09 12:47:2726楼 得分:10
    我的也是IE6 测试没问题.
    而且内存也没涨 最终稳定在98,7XX左右
    没使用CollectGarbage();
    说明大部份内存已经被释放了 可能有部分其他变量没有被释放而已.
    问题已经很明了了 如果没有别的问题 我也就此结束回复了.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • btbtd
    • 等级:
    发表于:2007-11-09 12:58:2827楼 得分:50

    这样问题貌似解决了...

    流程: 添加 -> 从内部删除 -> 释放内存...


    <html>
    <head>
    <script language="javascript">
    var arr = new Array();
    function c()
    {
        var div = document.createElement("DIV");
        var Main = document.getElementById("Main");
        document.body.appendChild(div);
        div.innerHTML = ' <input type="button" value="从内部删除" onclick="f();"/> <div style="position:absolute;top:110;left:110;width:1000px;height:1000px;-moz-opacity:0.07;filter:alpha(opacity=7);background-color:#000000"> </div>';
        arr.push(div);
        abcd.innerText = arr.length;
    }

    function f()
    {