【问题标题】:Javascript closure memory usage with on object member对象成员的 Javascript 闭包内存使用
【发布时间】:2017-02-26 21:59:37
【问题描述】:

我确定以前有人问过这个问题,但我没有找到。

以下示例 Javascript 闭包的内存使用情况是什么:

var f = (function(sz){
    var obj = {
        x : sz,
        y : new Array(sz),
    };

    var _x = obj.x;

    return function() {
        return obj.x;
    };
})(1000000);

应该保留多少obj 用于最终的关闭?将所有obj 保存在内存中,还是只保存obj.x?

我应该说我尝试(像新手一样)在 Google Chrome 中使用堆分析器。在关闭之前,总堆大小为 5.3MB。关闭后,当我将 obj.y 数组大小 (sz) 设置为 1,000,000 时,总堆大小为 13.2MB,f 保留 8MB。这表明obj.y 仍保留在内存中。当我将sz 更改为 10,000,000 时,堆大小为 81.9MB,f 保持健康的 80MB。与剩余的obj.y 一致。但是当我使用 100,000,000 的sz 时,配置文件显示的堆大小仅为 5.6M,而f 保留了 0.5MB。这告诉我obj.y 与垃圾一起被取出。并且在任何时候,f() 都会返回正确的值,因此可以推测,闭包按预期工作。

所以问题仍然存在,上面的闭包在内存中保存了什么?显然,我知道它可以是什么,但它应该是什么?

【问题讨论】:

  • 有一点需要注意,new Array(n) 不会(必然)占用太多内存,因为数组是用“空槽”创建的 - 试试new Array(sz).fill('') 看看区别
  • Afaik,闭包的垃圾收集是done per variable,但不是每个对象属性。它需要对对象的使用做出大量假设。

标签: javascript object closures


【解决方案1】:

我认为你可以通过在调试器中的return obj.x;行上放置一个断点来判断是否完整的对象包含在闭包中,然后添加一行来执行f持有的函数来触发它:

f();

在该断点处,您可以查询对象obj,您会看到它确实是整个对象。所以我会说,是的,所有的 obj 都基于此保存在闭包中。

我使用 node 和 Chrome 浏览器对此进行了测试,结果相同。也许其他 javascript 引擎对此进行了优化并表现不同。

关于垃圾收集,我想说的是,衡量垃圾收集器所做的事情是具有挑战性的,因为这种情况何时发生是相当不可预测的,并且取决于很多因素。

编辑 - 附加信息

我想更清楚地说明关闭的情况。在 JavaScript 中,垃圾收集只会发生在无法访问的事物(变量、函数……)上。只要某些东西是可访问的,它就不会被垃圾收集。

要查看这个函数的闭包,我们可以在控制台中使用console.dir() 命令。

这是一个示例控制台会话(Chrome 浏览器控制台):

> var f = (function(sz){
    var obj = {
        x : sz,
        y : new Array(sz),
    };

    var _x = obj.x;

    return function() {
        return obj.x;
    };
  })(1000000);
<- undefined
> console.dir(f)
  function anonymous()
    arguments: null
    caller: null
    length: 0
    name: ""
    prototype: Object
    __proto__: ()
    [[FunctionLocation]]: VM24461:9
    [[Scopes]]: Scopes[2]
      0: Closure
        obj: Object
          x: 1000000
          y: Array[1000000]
         __proto__: Object
      1: Global
<- undefined

现在,我们感兴趣的是在[[Scopes]] 下,我们可以看到该函数的闭包,而在该闭包中是obj。这意味着 obj 是可访问的,因此不能被垃圾收集。这也意味着 obj.y 是可访问的(通过 obj),因此也不能被垃圾回收。

希望这有助于提供进一步的清晰度。 console.dir() 非常方便查看更多关于闭包的信息。

【讨论】:

  • 我认为你是对的。如果尝试调试器(也像新手)并观察到相同的情况。但是当我替换为return _x 时,obj 不再是可观察到的。
猜你喜欢
  • 1970-01-01
  • 2012-10-07
  • 1970-01-01
  • 1970-01-01
  • 2012-07-23
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
相关资源
最近更新 更多