JavaScript对象的生命和内存泄漏

时间:2011-11-13 21:24:34

标签: javascript jquery memory-leaks

我已经对此进行了相当多的研究,但主要是将其他问题拼凑在一起,这仍然存在一些疑问。在一个不会随时刷新浏览器页面的应用程序中,可能会在不关闭的情况下生存很长时间(小时)(假设刷新页面或导航到另一个页面会重新启动js代码),确保对象的最佳方法是什么释放并且没有内存泄漏。

这些是我关注的特定情景:

以下所有代码都在一个揭示模块模式中。

mycode = function(){}()

函数中的变量,我确信这个变量很好地被GC收集了

function(){ var h = "ss";}

模块中的变量,当不再需要时,g = null吗?

var g;
function(){ g = "dd";}

最后jqXHR的生命:它在返回后被清理干净了吗?它是否应该在所有情况下都设置为null作为预防措施,是否保留在函数或模块中?

如果这样做,GC返回后是否清理了它?:

function(){
   var x = $.get();
   x.done = ...;
   x.fail = ...;
}

在执行此操作时,x返回后是否也会清理它?:

var x;
function(){
   x = $.get();
   x.done = ...;
   x.fail = ...;
}

最后,有没有办法清理所有变量并重新启动模块而不重新启动浏览器?

6 个答案:

答案 0 :(得分:7)

  

函数中的变量,我确信这个变量很好地被GC收集了

  

模块中的变量,当不再需要时,g = null吗?

不确定

  

最后jqXHR的生命:它在返回后被清理干净了吗?它是否应该在所有情况下都设置为null作为预防措施,是否保留在函数或模块中?

各种浏览器都有与XHR相关的错误导致onreadystatechange及其关闭的任何内容保持无法收集,除非开发人员小心地将其替换为虚拟值(xhr.onreadystatechange = new Function(''))但我相信jQuery为你处理这个。

  

最后,有没有办法清理所有变量并重新启动模块而不重新启动浏览器?

与页面关联的全局状态将占用浏览器内存,直到页面从浏览器历史记录堆栈中逐出。 location.replace可以帮助您杀死当前页面并将其替换为同一应用程序的新版本,而不会扩展历史记录堆栈。

  

将当前文档替换为提供的URL处的文档。与assign()方法的区别在于,使用replace()后,当前页面将不会保存在会话历史记录中,这意味着用户将无法使用“后退”按钮导航到该页面。

当您使用“模块”一词时,这不是一个对浏览器或其JavaScript解释器具有明确定义的术语,因此无法从内存中驱逐模块和模块。你有几件事需要担心,这可能会让事情记忆犹新:

  1. 引用已附加到DOM节点的JavaScript对象及其关闭的所有内容 - 事件处理程序是一个非常常见的示例。
  2. 实时setIntervalsetTimeout回调以及他们关闭的所有内容。
  3. 全局对象的属性及其关闭的所有内容。
  4. 正如您所说,某些主机对象的属性,如XHR实例,Web工作者回调等,以及(您猜对了)它们关闭的所有内容。
  5. 任何要卸载模块且只有模块的方案都需要处理所有这些,并找出哪些是模块的一部分,哪些不是。这是很多不同类型的清理。

答案 1 :(得分:1)

Javascript是一种垃圾收集语言。它依赖于垃圾收集器来清理未使用的内存。基本上,你必须相信GC会发挥作用。

GC将(最终,不一定立即)收集无法访问的对象。如果您有对象的引用,那么它可能仍在使用中,因此GC不会触及它。

如果您没有直接或间接引用该对象,则GC知道无法使用该对象,并且可以收集该对象。因此,您所要做的就是确保重置对该对象的任何引用。

但是,当收集对象时,GC不保证。你不应该担心这一点。

答案 2 :(得分:1)

你应该担心的唯一漏洞就是关闭。

function foo(a){
    var b = 10 + a;
    return function(c){
        return b + c;
    }
}

var bar = foo(20);
var baz = bar(5);

GC无法删除var b - 它超出了范围。对于IE来说,这是一个很大的问题,与Mozilla不同,Chrome更少。

答案 3 :(得分:1)

GC可以收集您无法再访问的每个变量。如果在函数内声明变量,则在退出函数后,可以删除变量 ,当计算机内存不足或任何其他时间。

当您执行XHR之类的异步函数时,这会变得更加复杂。 done fail 闭包可以访问外部函数中声明的所有变量。因此,只要完成失败可以执行,所有变量都必须保留在内存中。请求完成后,可以释放变量。

无论如何,你应该确保每个变量都被声明为尽可能深。

答案 4 :(得分:1)

根据经验,任何垃圾收集语言(例如,这适用于Java,.NET和JavaScript),您要做的是确保没有对您想要的内存块的延迟引用让GC清理干净。当GC查看内存块并发现程序中仍有某些内容引用它时,它将避免释放它。

关于jqXHR,在AJAX函数调用结束时将它们设置为null是没有意义的。一旦函数返回GC,AJAX成功/错误/完成的所有参数都将被释放,除非jQuery正在做一些奇怪的事情,比如保持对它们的引用。

答案 5 :(得分:0)

第一个带'g'的例子,g应该设置为null。否则它将保留指向“dd”的指针。

在第二个例子中,第一种情况下的'x'不需要设置为null,因为当周围函数退出时,该变量将“消失”。在第二种情况下,在函数外部使用'x','x'将保留分配给它的任何内容,并且在'x'设置为null或其他内容之前不会进行GC。