jQuery load() method memory leak?

2020-02-12 15:10发布

问题:

I have hunted around for answer to this one, and though have found related quesions, I couldn't quite find an exact match for this.

I have a fairly large app which is supposed to load pages into divs in another page using the jQuery.load() method. The problem I have is that when loading the same page over and over again into the same div, I see the memory of the browser increase substantially (memory leak). If I call $("*").unbind, I of course do not see a leak, but then everything has been reset, so this isn't reallya fix. The following code example reproduces this problem:

Test1.htm

<head>
   <title></title>
    <script type="text/javascript" language="javascript" src="Scripts/jquery-1.3.2.js"></script>
        <script type="text/javascript" language="javascript">
        <!--
            var i = 0;
        $(document).ready(function() {
            $("#btn").click(
                function() {
                    i++;
                    $("#Test1").load("Test2.htm", null, function() {
                        //$(document).trigger("test");
                    })
                    $("#count").html(i);
                });
        });
    //-->
    </script>
</head>
<body>
    <img id="btn" src="someimage.png" />
    <h3>We are loading Test2.htm into below div</h3>
    <div>
        Count loads =<span id="count">0</span>
    </div>
    <div id="Test1" style="border-style:solid">EMPTY</div>
</body>

Test2.htm = any old html page..

If you load Test1.htm and click the button mutliple times, you'll notice the browser memory steadily increasing. I believe the problem is that the loaded js and DOM elements are never set for garbage collection. In my real world system I have tried removing (elem.remove() or .empty()) the loaded elements, but this doens't really fix the problem. I also have many js files loaded using "src", which I replaced with $.getScript, this seems to have had made a small improvement. These are all workarounds thought, and I wanted to find a real solution for this problem. Any ideas?

回答1:

Edit: update due to more info provided about test2.htm (the page being loaded)

Original answer (for historical purposes): I don't actually see any leaks in the code/markup you have provided - is it possible the leak is in Test2.htm (which you haven't provided the code/markup for)?

New answer:

I would suggest that it it probably due to either multiple loads of jQuery, or other scripts you have in test2.htm.

Assuming jQuery does not leak by simply instantiating and then nullifying jQuery and $, loading multiple times will keep at least 2 copies of jQuery in memory. When loaded, jQuery keeps a backup of any previous versions of $ and jQuery in _$ and _jQuery - so you are going to have at least 2 copies of jQuery loaded when you use load() multiple times.

The above assumption is most likely not correct however - there is every chance that jQuery has leaks even if you "unload" it by setting $,jQuery,_$ and _jQuery to null - it's not really intended to be loaded multiple times like that (however I'm sure that they allow it intentionally, so you can use noConflict() to load and use two different versions of jQuery if necessary).

You can add a "selector" to a load URL. For example:

$("#Test1").load("Test2.htm body", null, function() { 
  //callback does nothing
});
//or
$("#Test1").load("Test2.htm div#the_Div_I_Want", null, function() { 
  //callback does nothing
});

I would suggest doing this if you are not interested in any scripts in the ajax result, or alternatively if you do want scripts, you'd need to choose a selector to disable only certain elements/scripts, e.g.

/* load with selector "all elements except scripts whose
   src attribute ends in 'jquery.js'" */
$("#Test1").load("Test2.htm :not(script[src$='jquery.js'])", null, function() { 
  //callback does nothing
});

Also of note is that if you leave out the "data" argument (you have it as null), and provide a function as the second argument, jQuery will correctly determine that the second argument is the callback, so

$("#Test1").load("Test2.htm :not(script[src$='jquery.js'])", function() { 
  //callback does nothing
});

is acceptible



回答2:

Hmm perhaps it's just something really basic, but if i set $.ajaxSetup({ cache: false }); before the load calls, I don't seem to get the problem. Now, of course my "real" code has this call, so why might I see a problem? I believe the Tabs UI extension is causing caching to be switched on (I don't actually believe this, but invoking the false cache call before each load seems to fix it!!)



回答3:

Ok so I finally found the problem and it's not a leak at all (which I suspected), it's simply the result of attaching multiple very complex handlers to the same trigger/event. I raised this question relating to that:

JQuery event model and preventing duplicate handlers