内存泄漏涉及的jQuery Ajax请求 [英] Memory leak involving jQuery Ajax requests

查看:426
本文介绍了内存泄漏涉及的jQuery Ajax请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个网页多数民众赞成泄漏内存在两个IE8和Firefox;在Windows进程管理器中显示的内存使用量只是不断增长的一段时间。

下面的页面请求unplanned.json的网址,这是一个静态文件,它不会改变(虽然我把我的缓存控制 HTTP标头无缓存来确保Ajax请求始终经过)。当它得到的结果,它清除了一个HTML表格,遍历JSON数组它得到了从服务器返回,并动态地添加行到一个HTML表格数组中的每个条目。然后它等待2秒,并且重复此过程。

下面是整个网页:

 < HTML> < HEAD>
    <冠军>测试页< /标题>
    <脚本类型=文/ JavaScript的
     的src =htt​​p://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js>&所述; /脚本>
< /头> <身体GT;
<脚本类型=文/ JavaScript的>
    功能开球(){
        $ .getJSON(unplanned.json,重置);
    }
    功能重置(行){
        $(#内容TBODY)空()。
        对于(VAR I = 0; I< rows.length;我++){
            $(&其中; TR>中
                +&其中; TD>中+行[I] .mpe_name +< / TD>中
                +&其中; TD>中+行[I]的.bin +< / TD>中
                +&其中; TD>中+行[I] .request_time +< / TD>中
                +&其中; TD>中+行[I] .filtered_delta +< / TD>中
                +&其中; TD>中+行[I] .failed_delta +< / TD>中
            +< / TR>中。)appendTo(#内容TBODY);
        }
        的setTimeout(开球,2000年);
    }
    $(开球);
< / SCRIPT>
<表ID =内容的边界=1的风格=宽度:100%;文字对齐:中心>
< THEAD>< TR>
    百分位> MPE< /第i个百分位>彬< /第i个百分位>在< /第i个百分位>过滤和LT; /第i个百分位>失败< /第i个
< / TR>< / THEAD>
< TBODY>< / TBODY>
< /表>
< /身体GT; < / HTML>
 

如果有帮助,这里是我送回来的JSON的例子(这是这个确切阵列wuith成千上万个条目,而不是一个):

  [
    {
        mpe_name:DBOSS-995,
        REQUEST_TIME:2009年9月18日11点51分06秒,
        斌:4,
        filtered_delta:1,
        failed_delta:1
    }
]
 

编辑:我已经接受Toran的极有帮助的答案,但我觉得我应该张贴一些额外的code,因为他的 removefromdom jQuery插件,有一定的局限性:

      
  • 这只是删除单个元素。所以,你不能给它像`$查询(#内容TBODY TR)`和期望它删除所有你所指定的元素。
  •   
  • 在您删除它必须有一个'ID`属性的元素。所以,如果我想删除我的`tbody`,那么我必须分配一个`ID`我`tbody`标签,否则它会给出一个错误。
  •   
  • 它消除了元件本身和它的所有后代,所以如果你只是想清空该元素,那么你就必须在事后重新创建(或修改插件来清空,而不是删除)。

因此​​,这里是我的网页上面修改为使用Toran的插件。为简单起见,我没有申请任何表现一般建议<一href="http://stackoverflow.com/questions/1455947/memory-leak-involving-jquery-ajax-requests/1456073#1456073">offered彼得。这里的页面现在不再内存泄漏:

 &LT; HTML&GT;
&LT; HEAD&GT;
    &LT;冠军&GT;测试页&LT; /标题&GT;
    &LT;脚本类型=文/ JavaScript的SRC =htt​​p://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js&GT;&LT; / SCRIPT&GT;
&LT; /头&GT;
&LT;身体GT;
&LT;脚本类型=文/ JavaScript的&GT;
&LT;! - 
    $ .fn.removefromdom =功能(S){
        如果收益率(这个!);

        VAR EL =的document.getElementById(this.attr(ID));

        如果(EL!)回报;

        VAR斌=的document.getElementById(IELeakGarbageBin);

        //删除埃尔之前,递归删除其所有的孩子。
        而(el.childNodes.length大于0){
            如果(!斌){
                斌= document.createElement方法(DIV);
                bin.id =IELeakGarbageBin;
                document.body.appendChild(箱);
            }

            bin.appendChild(el.childNodes [el.childNodes.length  -  1]);
            bin.innerHTML =;
        }

        el.parentNode.removeChild(EL);

        如果(!斌){
            斌= document.createElement方法(DIV);
            bin.id =IELeakGarbageBin;
            document.body.appendChild(箱);
        }

        bin.appendChild(EL);
        bin.innerHTML =;
    };

    变种复位= 0;
    功能开球(){
        $ .getJSON(unplanned.json,重置);
    }
    功能重置(行){
        $(#内容TBODY)removefromdom()。
        $(#内容)追加('&LT; TBODY ID =id_field_required&GT;&LT; / TBODY&GT;');
        对于(VAR I = 0; I&LT; rows.length;我++){
            $(#内容TBODY)追加(&LT; TR&GT;&LT; TD&gt;中+行[I] .mpe_name +&LT; / TD&gt;中
                +&其中; TD&gt;中+行[I]的.bin +&LT; / TD&gt;中
                +&其中; TD&gt;中+行[I] .request_time +&LT; / TD&gt;中
                +&其中; TD&gt;中+行[I] .filtered_delta +&LT; / TD&gt;中
                +&其中; TD&gt;中+行[I] .failed_delta +&LT; / TD&GT;&LT; / TR&gt;中);
        }
        复位++;
        $(#信息)HTML(内容设置很多次:+复位);
        的setTimeout(开球,2000年);
    }
    $(开球);
//  - &GT;
&LT; / SCRIPT&GT;
&LT; D​​IV ID =消息的风格=颜色:红色&GT;&LT; / DIV&GT;
&LT;表ID =内容的边界=1的风格=宽度:100%;文字对齐:中心&GT;
&LT; THEAD&GT;&LT; TR&GT;
    百分位&GT; MPE&LT; /第i个
    百分位&GT;彬&LT; /第i个
    百分位&gt;在&LT; /第i个
    百分位&GT;过滤和LT; /第i个
    百分位&GT;失败&LT; /第i个
&LT; / TR&GT;&LT; / THEAD&GT;
&LT; TBODY ID =id_field_required&GT;&LT; / TBODY&GT;
&LT; /表&gt;
&LT; /身体GT;
&LT; / HTML&GT;
 

进一步编辑:我会留下我的问题没有改变,虽然这是值得注意的是,此内存泄漏无关使用Ajax。事实上,以下code将内存泄漏一样的,并可以很容易地解决了Toran的 removefromdom jQuery插件:

 功能重置(){
    $(#内容TBODY)空()。
    对于(VAR I = 0; I&LT; 1000;我++){
        $(#内容TBODY)追加(&LT; TR&GT;&LT; TD&gt;中+DBOSS-095+&LT; / TD&gt;中
            +&其中; TD&gt;中+ 4 +&所述; / TD&gt;中
            +&其中; TD&gt;中+2009年9月18号11点五十一分06秒+&所述; / TD&gt;中
            +&其中; TD&gt;中+ 1 +&所述; / TD&gt;中
            +&其中; TD&gt;中+ 1 +&所述; / TD&GT;&所述; / TR&gt;中);
    }
    的setTimeout(复位,2000年);
}
$(重置);
 

解决方案

我不知道为什么Firefox是不开心瓦特/这一点,但我可以从经验说,在IE6 / 7/8,你必须设置的innerHTML = ;在对象上要从DOM中删除。 (如果你创造了这个DOM元素动态的即是)

$(#内容TBODY)空(); 可能不会释放这些动态生成的DOM元素

相反,你可以试试下面的(这是一个jQuery插件,我写来解决这个问题)。

  jQuery.fn.removefromdom =功能(S){
    如果收益率(这个!);

    VAR箱= $(#IELeakGarbageBin);

    如果(!bin.get(0)){
        宾= $(&LT; D​​IV ID ='IELeakGarbageBin'&GT;&LT; / DIV&gt;中);
        $(机构)追加(箱);
    }

    $(本)。儿童()。每个(
            功能() {
                bin.append(本);
                的document.getElementById(IELeakGarbageBin)的innerHTML =。
            }
    );

    this.remove();

    bin.append(本);
    的document.getElementById(IELeakGarbageBin)的innerHTML =。
};
 

您会调用这个像这样: $(#内容)removefromdom();

这里唯一的问题是,你需要重新创建表要建立它每次。

另外,如果这确实解决您的问题,在IE浏览器,你可以阅读更多关于这在博客<一href="http://toranbillups.com/blog/archive/2009/04/21/Cleanup-for-dynamically-generated-DOM-elements-in-IE">post我在今年年初写的时候我遇到了同样的问题。

修改我更新的插件上面是95%的JavaScript现在有空,所以它使用更多的jQuery比previous版本。你仍然会发现,我必须使用innerHTML的,因为jQuery的功能HTML();不会对IE6的行为相同/ 7/8

I have a webpage that's leaking memory in both IE8 and Firefox; the memory usage displayed in the Windows Process Explorer just keeps growing over time.

The following page requests the "unplanned.json" url, which is a static file that never changes (though I do set my Cache-control HTTP header to no-cache to make sure that the Ajax request always goes through). When it gets the results, it clears out an HTML table, loops over the json array it got back from the server, and dynamically adds a row to an HTML table for each entry in the array. Then it waits 2 seconds and repeats this process.

Here's the entire webpage:

<html> <head>
    <title>Test Page</title>
    <script type="text/javascript"
     src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
</head> <body>
<script type="text/javascript">
    function kickoff() {
        $.getJSON("unplanned.json", resetTable);
    }
    function resetTable(rows) {
        $("#content tbody").empty();
        for(var i=0; i<rows.length; i++) {
            $("<tr>"
                + "<td>" + rows[i].mpe_name + "</td>"
                + "<td>" + rows[i].bin + "</td>"
                + "<td>" + rows[i].request_time + "</td>"
                + "<td>" + rows[i].filtered_delta + "</td>"
                + "<td>" + rows[i].failed_delta + "</td>"
            + "</tr>").appendTo("#content tbody");
        }
        setTimeout(kickoff, 2000);
    }
    $(kickoff);
</script>
<table id="content" border="1" style="width:100% ; text-align:center">
<thead><tr>
    <th>MPE</th> <th>Bin</th> <th>When</th> <th>Filtered</th> <th>Failed</th>
</tr></thead>
<tbody></tbody>
</table>
</body> </html>

If it helps, here's an example of the json I'm sending back (it's this exact array wuith thousands of entries instead of just one):

[
    {
        mpe_name: "DBOSS-995",
        request_time: "09/18/2009 11:51:06",
        bin: 4,
        filtered_delta: 1,
        failed_delta: 1
    }
]

EDIT: I've accepted Toran's extremely helpful answer, but I feel I should post some additional code, since his removefromdom jQuery plugin has some limitations:

  • It only removes individual elements. So you can't give it a query like `$("#content tbody tr")` and expect it to remove all of the elements you've specified.
  • Any element that you remove with it must have an `id` attribute. So if I want to remove my `tbody`, then I must assign an `id` to my `tbody` tag or else it will give an error.
  • It removes the element itself and all of its descendants, so if you simply want to empty that element then you'll have to re-create it afterwards (or modify the plugin to empty instead of remove).

So here's my page above modified to use Toran's plugin. For the sake of simplicity I didn't apply any of the general performance advice offered by Peter. Here's the page which now no longer memory leaks:

<html>
<head>
    <title>Test Page</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
<!--
    $.fn.removefromdom = function(s) {
        if (!this) return;

        var el = document.getElementById(this.attr("id"));

        if (!el) return;

        var bin = document.getElementById("IELeakGarbageBin");

        //before deleting el, recursively delete all of its children.
        while (el.childNodes.length > 0) {
            if (!bin) {
                bin = document.createElement("DIV");
                bin.id = "IELeakGarbageBin";
                document.body.appendChild(bin);
            }

            bin.appendChild(el.childNodes[el.childNodes.length - 1]);
            bin.innerHTML = "";
        }

        el.parentNode.removeChild(el);

        if (!bin) {
            bin = document.createElement("DIV");
            bin.id = "IELeakGarbageBin";
            document.body.appendChild(bin);
        }

        bin.appendChild(el);
        bin.innerHTML = "";
    };

    var resets = 0;
    function kickoff() {
        $.getJSON("unplanned.json", resetTable);
    }
    function resetTable(rows) {
        $("#content tbody").removefromdom();
        $("#content").append('<tbody id="id_field_required"></tbody>');
        for(var i=0; i<rows.length; i++) {
            $("#content tbody").append("<tr><td>" + rows[i].mpe_name + "</td>"
                + "<td>" + rows[i].bin + "</td>"
                + "<td>" + rows[i].request_time + "</td>"
                + "<td>" + rows[i].filtered_delta + "</td>"
                + "<td>" + rows[i].failed_delta + "</td></tr>");
        }
        resets++;
        $("#message").html("Content set this many times: " + resets);
        setTimeout(kickoff, 2000);
    }
    $(kickoff);
// -->
</script>
<div id="message" style="color:red"></div>
<table id="content" border="1" style="width:100% ; text-align:center">
<thead><tr>
    <th>MPE</th>
    <th>Bin</th>
    <th>When</th>
    <th>Filtered</th>
    <th>Failed</th>
</tr></thead>
<tbody id="id_field_required"></tbody>
</table>
</body>
</html>

FURTHER EDIT: I'll leave my question unchanged, though it's worth noting that this memory leak has nothing to do with Ajax. In fact, the following code would memory leak just the same and be just as easily solved with Toran's removefromdom jQuery plugin:

function resetTable() {
    $("#content tbody").empty();
    for(var i=0; i<1000; i++) {
        $("#content tbody").append("<tr><td>" + "DBOSS-095" + "</td>"
            + "<td>" + 4 + "</td>"
            + "<td>" + "09/18/2009 11:51:06" + "</td>"
            + "<td>" + 1 + "</td>"
            + "<td>" + 1 + "</td></tr>");
    }
    setTimeout(resetTable, 2000);
}
$(resetTable);

解决方案

I'm not sure why firefox isn't happy w/ this but I can say from experience that in IE6/7/8 you must set innerHTML = ""; on the object you want removed from the DOM. (if you created this DOM element dynamically that is)

$("#content tbody").empty(); might not be releasing these dynamically generated DOM elements.

Instead try something like the below (this is a jQuery plugin I wrote to solve the issue).

jQuery.fn.removefromdom = function(s) {
    if (!this) return;

    var bin = $("#IELeakGarbageBin");

    if (!bin.get(0)) {
        bin = $("<div id='IELeakGarbageBin'></div>");
        $("body").append(bin);
    }

    $(this).children().each(
            function() {
                bin.append(this);
                document.getElementById("IELeakGarbageBin").innerHTML = "";
            }
    );

    this.remove();

    bin.append(this);
    document.getElementById("IELeakGarbageBin").innerHTML = "";
};

You would call this like so: $("#content").removefromdom();

The only issue here is that you need to re-create your table each time you want to build it.

Also, if this does solve your issue in IE you can read more about this in a blog post that I wrote earlier this year when I came across the same problem.

Edit I updated the plugin above to be 95% JavaScript free now so it's using more jQuery than the previous version. You will still notice that I have to use innerHTML because the jQuery function html(""); doesn't act the same for IE6/7/8

这篇关于内存泄漏涉及的jQuery Ajax请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆