I'm trying to figure out why IE is leaking memory when wrapping an AJAX-ly requested HTML page in a jQuery object for processing. The user may visit the page and let it sit for many minutes or hours, so the page uses jQuery's ajax
method a few times a minute to get new data, and then I replace important parts of the page with the new pre-rendered data.
At this point, I've narrowed it down to a single call - when $(data)
is invoked to wrap the HTML string, memory spikes a little, and doesn't ever seem to be garbage collected. Over time many hundreds of MB are used and I'm forced to reload the page or restart IE.
This fiddle is able to reproduce the issue. It uses AJAX to request a page, and then calls $(data)
in a tight loop in order to exaggerate the leak. Chrome and Firefox both seem to react as I'd expect (memory is reclaimed), but IE is behaving badly. Surprise.
Using Process Explorer, I see memory consumption spike dramatically after running the above fiddle just two times.
I'm currently using IE9 in standards mode.
Why is this happening? Is there a workaround?
Update
Here's a fiddle that demonstrates the issue without using AJAX.
I've found a workaround the the problem I described above.
In troubleshooting this, I tried a variety of things to prevent the leak from happening. The solution that I came up with was to ditch using $.ajax
to retrieve the data and $()
to wrap the results. Instead I used $('#destination').load('sourceUrl #selector')
(see documentation) to shove the data into a hidden div and then manipulate the result that way.
Turns out $.load
uses $.parseHTML
under the covers to manipulate the results and shove them in the specified location (and $()
apparently doesn't). See here for source line.
$(htmlText)
leaks
$(bodyText)
doesn't leak
$.parseHtml(htmlText)
slowly leaks(?)
$.parseHtml(bodyText)
doesn't leak
Here's a fiddle to demonstrate.
I don't know why it behaves the way it does, but the short of it seems to be: avoid parsing full HTML documents whenever possible.
I was seeing what you were seeing, when I changed the code to reallocate the function each time success gets called, magically it didn't leak (atleast in my environment.)
So, my solution is stupid, but it appears to work for me. Does it work for you?
$(function(){
$.ajaxSetup({ cache: false });
$('#go').click(performCall);
});
function performCall() {
$('#timestamp').text('Working...');
$.ajax({
url: 'http://fiddle.jshell.net/',
success: function(){
var func = function(data, textStatus, jqXHR) {
$('#timestamp').text('Done at ' + new Date());
for(var x = 0; x < 100; x++) {
var $a = $(data);
}
};
func();
}
});
}
http://jsfiddle.net/tCvUw/