jQuery Memory Leak Suspicion

我正在为XML做一个AJAX请求。 我这样做每一秒。 我注意到我的内存使用量增长到数百兆字节。 正如您可能想象的那样,客户对此并不满意。 在各个地方做了一些阅读后,我怀疑function关闭引起了我的头痛。 我正在寻找可以获得的任何validation以及如何解决它的任何帮助。

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 (); 

编辑我已经结合了一些人的想法和一些成功的处理程序内部。 我看到增长率较小,但不是很多。

为了避免任何新创建的函数(上下文)在此处关闭其父作用域,您只需要在那里删除setTimeout中的匿名函数。 所以

  setTimeout(self.timeoutHandler, 750); 

但是,即使该闭包将覆盖父上下文,任何一半体面的垃圾收集器(像任何现代浏览器一样)都会注意到它并在方法触发后释放内存。 你没有提到的非常重要的事情是你注意到了哪种浏览器的行为。 例如,Firefox垃圾收集器工作..非常不可思议(至少对我而言)。 它将允许越来越多的内存被使用,然后在某些时候,它将再次释放一大块。

要查看发生了什么,请使用Firefox并在脚本运行时查看about:memory 。 在那里你会看到记忆的去向。 如果内存使用量增加一段时间,我不会担心。 看看它,如果这是你的所有代码,内存应该迟早被释放。

当你保持对事物的引用时,内存会增长。 当你不小心这样做时,这是一个泄漏。

在这种情况下,你的函数timeoutHandler自己调用,然后再次调用……它永远无法清理调用堆栈。 我敢打赌这是你的泄密。

要避免此问题,请使用setInterval 。 它的工作方式与setTimeout完全相同,但它会每隔几毫秒调用一次该函数,直到用clearTimeout清除它(或直到世界结束)。

缺点是你不能很好地计时,你的当前实现总是在每次调用后等待750毫秒。 我想你可以做一些花哨的东西,它仍然可以让你把它计时(用Date来检查时间),但这不是我在10秒内写的东西:P

我只想把我的两分钱扔进去,但我同意jAndy(+1)。 但是,我会生成一次绑定回调一次,而不是在回调的迭代中创建一个新的闭包(理论上可以使范围和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(); 

编辑

这是一个带有上述代码的jsFiddle ,我看了一段时间的内存管理,但在任何意义上都不足以确定。

你的超时function

 setTimeout(self.timeoutHandler, 750); 

可能导致内存泄漏。 虽然成功:回调能够在完成后退出,但在setTimeout回调中可能没有空的上下文导致循环循环。 你应该取出匿名函数来结束这样的事情:

 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); } }); }; } 

这应该只回拨一次。