javascript - JavaScript 闭包是如何被垃圾回收的

标签 javascript internet-explorer google-chrome firefox garbage-collection

我记录了以下 Chrome bug ,这导致我的代码中有许多严重且不明显的内存泄漏:

(这些结果使用 Chrome 开发工具的 memory profiler ,它运行 GC,然后对所有未垃圾收集的内容进行堆快照。)

在下面的代码中,someClass 实例被垃圾回收(好):

var someClass = function() {};

function f() {
  var some = new someClass();
  return function() {};
}

window.f_ = f();

但在这种情况下不会被垃圾收集(坏):

var someClass = function() {};

function f() {
  var some = new someClass();
  function unreachable() { some; }
  return function() {};
}

window.f_ = f();

以及对应的截图:

screenshot of Chromebug

如果对象被同一上下文中的任何其他闭包引用,则闭包(在本例中为 function() {})似乎保持所有对象“事件”,无论是否这个闭包本身甚至是可以到达的。

我的问题是关于其他浏览器(IE 9+ 和 Firefox)中闭包的垃圾收集。我对 webkit 的工具很熟悉,比如 JavaScript heap profiler,但是我对其他浏览器的工具知之甚少,所以我一直无法测试。

在这三种情况下,IE9+ 和 Firefox 会垃圾收集 someClass 实例吗?

最佳答案

据我所知,这不是错误,而是预期的行为。

来自 Mozilla 的 Memory management page :“截至 2012 年,所有现代浏览器都配备了标记和清除垃圾收集器。” “限制:对象需要明确地不可访问

在您失败的示例中, some 在闭包中仍然可以访问。我尝试了两种方法使其无法访问并且都可以工作。当你不再需要它时,要么设置 some=null,要么设置 window.f_ = null; 它将消失。

更新

我已经在 Windows 上的 Chrome 30、FF25、Opera 12 和 IE10 中尝试过。

standard没有说任何关于垃圾收集的事情,但给出了一些应该发生的事情的线索。

  • 第 13 节函数定义,第 4 步:“让闭包成为创建 13.2 中指定的新函数对象的结果”
  • 第 13.2 节“范围指定的词法环境”(范围 = 闭包)
  • 第 10.2 节词汇环境:

"The outer reference of a (inner) Lexical Environment is a reference to the Lexical Environment that logically surrounds the inner Lexical Environment.

An outer Lexical Environment may, of course, have its own outer Lexical Environment. A Lexical Environment may serve as the outer environment for multiple inner Lexical Environments. For example, if a Function Declaration contains two nested Function Declarations then the Lexical Environments of each of the nested functions will have as their outer Lexical Environment the Lexical Environment of the current execution of the surrounding function."

因此,函数将可以访问父级的环境。

所以,some 应该在返回函数的闭包中可用。

那为什么它不总是可用?

Chrome 和 FF 似乎很聪明,可以在某些情况下消除该变量,但在 Opera 和 IE 中,some 变量在闭包中可用(注意:查看此设置断点on return null 并检查调试器)。

GC可以改进以检测函数中是否使用了some,但这会很复杂。

一个不好的例子:

var someClass = function() {};

function f() {
  var some = new someClass();
  return function(code) {
    console.log(eval(code));
  };
}

window.f_ = f();
window.f_('some');

在上面的例子中,GC 无法知道变量是否被使用(代码经过测试并且在 Chrome30、FF25、Opera 12 和 IE10 中工作)。

如果通过为 window.f_ 分配另一个值来破坏对对象的引用,则会释放内存。

在我看来这不是错误。

关于javascript - JavaScript 闭包是如何被垃圾回收的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19798803/

相关文章:

javascript - jquery 淡入淡出损坏

Sonar 中的 javascript 代码覆盖率

javascript - 从 AngularJS 应用程序访问硬盘上的文件

html - 仅 IE9 字体问题(呈现回退字体)

internet-explorer - 使用 CSS 设置宽度时内联 block 元素出现问题

Javascript 字符串计数与 rtrim

javascript - 在新选项卡中打开链接在 IE10 中不起作用

html - iframe 在 Chrome 中无法正确调整大小

javascript - 没有 U2F Chrome 扩展的 U2F 支持

javascript - 为什么在 Chrome 扩展程序中使用 RequireJS 调用时 chrome.tabs.query() 不返回选项卡的 URL?