Memory Leak When Pulling JSON from WEB

2019-01-26 22:57发布

问题:

I've spent days on this and hit it from every angle I can think of. I'm working on a simple windows 7 gadget. This script will pull JSON data from a remote web server and put it on the page. I'm using jQuery 1.6.2 for the $.getJSON. Script consumes more memory each loop.

var count = 1;

$(document).ready(function () {
    updateView();
});

function updateView(){
    $("#junk").html(count);
    count++;
    $.getJSON( URL + "&callback=?", populateView);
    setTimeout( updateView, 1000 );
}

function populateView(status) {
    $("#debug").html(status.queue.mbleft + " MB Remaining<br>" + status.queue.mb + " MB Total");
}

Any help would be greatly appreciated....Thank you!

EDIT: Add JSON data sample

?({"queue":{"active_lang":"en","paused":true,"session":"39ad74939e89e6408f98998adfbae1e2","restart_req":false,"power_options":true,"slots":[{"status":"Queued","index":0,"eta":"unknown","missing":0,"avg_age":"2d","script":"None","msgid":"","verbosity":"","mb":"8949.88","sizeleft":"976 MB","filename":"TestFile#1","priority":"Normal","cat":"*","mbleft":"975.75","timeleft":"0:00:00","percentage":"89","nzo_id":"-n3c6z","unpackopts":"3","size":"8.7 GB"}],"speed":"0  ","helpuri":"","size":"8.7 GB","uptime":"2d","refresh_rate":"","limit":0,"isverbose":false,"start":0,"version":"0.6.5","new_rel_url":"","diskspacetotal2":"931.51","color_scheme":"gold","diskspacetotal1":"931.51","nt":true,"status":"Paused","last_warning":"","have_warnings":"0","cache_art":"0","sizeleft":"976 MB","finishaction":null,"paused_all":false,"cache_size":"0 B","finish":0,"new_release":"","pause_int":"0","mbleft":"975.75","diskspace1":"668.52","scripts":[],"categories":["*"],"darwin":false,"timeleft":"0:00:00","mb":"8949.88","noofslots":1,"nbDetails":false,"eta":"unknown","quota":"","loadavg":"","cache_max":"0","kbpersec":"0.00","speedlimit":"","webdir":"","queue_details":"0","diskspace2":"668.52"}})

EDIT 2: Stripped code down to this and it still leaks. I think that eliminates traversing the DOM as a contributor.

$(document).ready(function () {
    setInterval(updateView, 1000);
});

function updateView(){
    $.getJSON( URL + "&callback=?", populateView);
}

function populateView(status) {
}

EDIT 3: It's not jQuery. I removed jQuery and did it with straight js. Still leaks.

function init(){
    setInterval(updateView, 1000);
}

function updateView(){
    var xhr = new XMLHttpRequest();
    xhr.open("GET", URL, false);
    xhr.setRequestHeader( "If-Modified-Since", "0");
    xhr.send('');
}

So...if it's not jQuery, not just in IE (Chrome too). What the heck?! Ideas?

Thank you!

回答1:

Edit 2:

If it's actually taskmanager showing the leak here, then I think the next step is to investigate IE, as I believe that IE is then engine used to host Windows Widgets.

If you can recreate your script in a little html file you can run this tool and have a look if it's IE that's doing it:

http://blogs.msdn.com/b/gpde/archive/2009/08/03/javascript-memory-leak-detector-v2.aspx

Also, are you running IE8 or 9 ?


Edit:

Based on the JSON string in the Op; basically the problem is misleading here. the bit of javascript posted is working perfectly fine.

The Server producing the JSON is the one that's showing a difference in memory usage, I would investigate the website/endpoint that's creating that JSON and seeing what the issue is.


Just had a thought,

$.getJSON is just a shorthand function for jQuery's $.ajax call.

I wonder if it makes a different if you change your code to use $.ajax but specifically add the cache mechanism to it:

$.ajax({
  url: URL + "&callback=?",
  dataType: 'json',
  cache: false,
  success: populateView
});

That might stop it trying to store it in memory perhaps, and depending on your browser, it might be showing more memory because you just haven't had your garbage collected, so to speak.



回答2:

I have the feeling that the setTimeout function within the updateView is causing this behaviour. To test this you can modify your code to:

$(document).ready(function () {
   setInterval(updateView, 1000);
});

function updateView(){
    $("#junk").html(count);
    count++;
    $.getJSON( URL + "&callback=?", populateView);
}

function populateView(status) {
    $("#debug").html(status.queue.mbleft + " MB Remaining<br>" + status.queue.mb + " MB Total");
}

EDIT: The setInterval function will execute the passed in function over and over every x miliseconds. Here to the docs.

EDIT 2: Another performance loose (Although it might not be critical to the issue) is that you are traversing the DOM every second to find the $('#debug') element. You could store that and pass it in as:

        $(document).ready(function () {
            var debug = $('#debug'); 
            var junk = $('#junk')          ;
            setInterval(function(){updateView(debug, junk)}, 1000);

        });

        function updateView(debug, junk){
           junk.html(count);
            count++;
            $.getJSON( URL + "&callback=?", function(status){populateView(status,debug)});
        }

        function populateView(status) {
            debug.html(status.queue.mbleft + " MB Remaining<br>" + status.queue.mb + " MB Total");
        }

Edit 3: I have changed the code above because I forgot to take in the response from the server. Assuming that queue is a property of the returned JSON then the code should be as above.

Edit 4: This is a very interesting issue. Another approach then. Lets assume then that there is still some client side scripts that are clogging the memory. What could this be? As far as is I understand the only two things left are the setInterval and the $.getJSON function. The $.getJSON function is a simple ajax request wrapper which fires a request and waits for the response from the server. The setInterval function is a bit more peculiar one because it will set up timers, fire functions, etc.

I think if you manage to mimic this on your server or even just refresh this webpage in your browser every second/5 secs you you will be able to see whether it is the client or the server that processes your request.



回答3:

Found this thread trying to find the underlying reason to this problem because I also had a similar problem recently although my memory would increase about 1Mb per minute... I pretty much isolated it to json parsing. Run the ajax command with type: 'text', and you should see that the memory gets cleaned up.

I found a library json_parse.js which recursively parses the json data using the JS engine (not eval). I manually parse the text data to json in the success callback and this works well.