简体   繁体   English

jQuery Memory Leak Suspicion

[英]jQuery Memory Leak Suspicion

I am making an AJAX request for XML. 我正在为XML做一个AJAX请求。 I am doing this every second. 我这样做每一秒。 I notice that my memory usage grows into the hundreds of megabytes. 我注意到我的内存使用量增长到数百兆字节。 As you might imagine, the customer is not happy with this. 正如您可能想象的那样,客户对此并不满意。 After doing some reading in various places, I suspect that function closures are causing my headache. 在各个地方做了一些阅读后,我怀疑功能关闭引起了我的头痛。 I am looking for any verification that can be had as well as any help for how to fix it. 我正在寻找可以获得的任何验证以及如何解决它的任何帮助。

function PageManager () {
    var self = this;

    self.timeoutHandler = function () {
        $.ajax ({
            url: 'URLtoXML',
            type: 'post',
            cache: false,
            context: self,
            success: function (data) {
                var slf = this;
                var xmlDoc = $($.parseXML (data));
                xmlDoc.find ("tag_label").each (function () {
                    self.val = parseInt ($.trim ($(this).text ()));
                }
                setTimeout (slf.timeoutHandler, 750);
            }
        });
    }
}

var pm = new PageManager ();
pm.timeoutHandler ();

EDIT I have incorporated some people's ideas and a little of the success handler internals. 编辑我已经结合了一些人的想法和一些成功的处理程序内部。 I see a smaller growth rate, but not by much. 我看到增长率较小,但不是很多。

To avoid that any newly created function (context) is closing over its parent scope here, you would just need to get rid of the anonymous function in setTimeout there. 为了避免任何新创建的函数(上下文)在此处关闭其父作用域,您只需要在那里删除setTimeout中的匿名函数。 So 所以

 setTimeout(self.timeoutHandler, 750);

However, even if that closure would clouse over the parent(s) contexts, any half decent garbage collector (like any modern browser have) will notice it and free the memory after the method has fired. 但是,即使该闭包将覆盖父上下文,任何一半体面的垃圾收集器(像任何现代浏览器一样)都会注意到它并在方法触发后释放内存。 The very important thing you didn't mention is on which browser you noticed the behavior. 你没有提到的非常重要的事情是你注意到了哪种浏览器的行为。 The Firefox garbage collector for instance, works .. pretty unpretictable (at least to me). 例如,Firefox垃圾收集器工作..非常不可思议(至少对我来说)。 It'll allow for more and more memory to get used and then on some point, it will release a huge chunk again. 它将允许越来越多的内存被使用,然后在某些时候,它将再次释放一大块。

To see what is going on, use Firefox and have a look into about:memory while your script is running. 要查看发生了什么,请使用Firefox并在脚本运行时查看about:memory There you will see where the memory goes. 在那里你会看到记忆的去向。 I would not be worried if the memory usage increases for a while. 如果内存使用量增加一段时间,我不会担心。 Look at it, if that is all of your code, the memory should get freed sooner or later. 看看它,如果这是你的所有代码,内存应该迟早被释放。

Your timeout function 你的超时功能

setTimeout(self.timeoutHandler, 750);

may be causing memory leak. 可能导致内存泄漏。 Although the success: callback is able to exit after finished, there may not be an empty context in a setTimeout callback causing a circular loop. 虽然成功:回调能够在完成后退出,但在setTimeout回调中可能没有空的上下文导致循环循环。 Youl should take out the anonymous function to end up something like this: 你应该取出匿名函数来结束这样的事情:

var pManager = new PageManager ();
pManager.timeoutHandler();

function PageManager () {
var ret  = (function(self) { 
    return function() { self.timeoutHandler(); };
})(this);

this.timeoutHandler = function () {
    $.ajax ({
        url: '/echo/json/',
        type: 'post',
        cache: false,
        success: function (data) {
            setTimeout (ret, 750);
        }
    });
};
}

This should only call back once. 这应该只回拨一次。

Memory grows when you keep references to things. 当你保持对事物的引用时,内存会增长。 It's a leak when you accidentally do this. 当你不小心这样做时,这是一个泄漏。

In this case your function timeoutHandler calls itself, and again, and again ... It can never clean up the call stack. 在这种情况下,你的函数timeoutHandler自己调用,并且再一次......它永远无法清理调用堆栈。 I'll bet this is your leak. 我敢打赌这是你的泄密。

To avoid this problem use setInterval . 要避免此问题,请使用setInterval It works exactly like setTimeout but it will keep calling the function every milliseconds until you clear it with clearTimeout (or until the world ends). 它的工作方式与setTimeout完全相同,但它会每隔几毫秒调用一次该函数,直到用clearTimeout清除它(或直到世界结束)。

The down side is that you can't time it very well, your current implementation always waits 750 milliseconds after each call. 缺点是你不能很好地计时,你的当前实现总是在每次调用后等待750毫秒。 I suppose you could do something fancy that will still allow you time it well (using Date to check the time), but it's not something I could write in 10 seconds :P 我想你可以做一些花哨的东西,它仍然可以让你把它计时(使用Date来检查时间),但这不是我在10秒钟内写的东西:P

I'm just going to throw my two cents in but i agree jAndy (+1). 我只想把两分钱扔进去,但我同意jAndy(+1)。 However, I would generate a single bound callback once, rather than creating a new closure on ever iteration of the callback (which in theory could keep the scope and the xml data alive for a lot longer than you want. I would suggest another alternative like this: 但是,我会生成一次绑定回调,而不是在回调的迭代中创建一个新的闭包(理论上可以使范围和xml数据保持活动的时间比你想要的要长很多。我建议另外一个像这个:

function PageManager () {
    var callback  = (function(self) { 
        return function() { self.timeoutHandler(); };
    })(this); // only one callback

    this.timeoutHandler = function () {
        $.ajax ({
            url: '/echo/json/',
            type: 'post',
            cache: false,
            data: {a:Math.random() },
            success: function (data) {
                //var xmlDoc = $($.parseXML (data));
                // Processing of XML
                //alert("data");
                setTimeout (callback, 750);
            }
        });
    };
}

var pm = new PageManager ();
pm.timeoutHandler();

Edit 编辑

Here is a jsFiddle with the above code, and I watched the memory management for a little while, but not nearly enough to be conclusive in any sense. 这是一个带有上述代码的jsFiddle ,我看了一段时间的内存管理,但在任何意义上都不足以确定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM