【问题标题】:Freeing JavaScript object释放 JavaScript 对象
【发布时间】:2010-12-23 23:20:33
【问题描述】:

我在看http://www.javascriptkit.com/javatutors/oopjs.shtml的例子

var person = new Object()
person.name = "Tim Scarfe"
person.height = "6Ft"

但没有提及如何“释放”它以避免内存泄漏。

下面的代码会释放它吗?

person = null;
  1. 如何使用“new Object() 释放 JavaScript 对象?
  2. 如何释放使用“new Array(10)”分配的 JavaScript 数组?
  3. 如何释放使用“var json = {"width": 480, "height": 640}" 分配的 JavaScript JSON?

提前感谢您的帮助。

【问题讨论】:

  • 不是 JavaScript JSON。它只是对象文字表示法。如果它是一个字符串,它只是 JSON。另见:benalman.com/news/2010/03/theres-no-such-thing-as-a-json/…
  • 题外话:您从该站点获得的示例代码不是很好。 1. new Object() => {}; 2.它依赖于自动插入分号,如果不是魔鬼的产物,它仍然是你绝对不应该依赖的东西; 3. 好吧,这一点并不可怕,但是,嘿,为什么不教文字符号呢? var person = {name: "Tim Scarfe", height: "6Ft"}; 但实际上它是#2,在较小程度上是#1,这让我很“讨厌”。

标签: javascript


【解决方案1】:

您不必显式地“释放”JavaScript 对象。所有标准 JavaScript 主机/环境都根据对象是否可以再访问来使用垃圾收集。 (可能有一些小众主机,例如一些用于嵌入式系统的主机,它们不会这样做;如果是这样,它们将提供自己的显式释放事物的方法。)如果无法再访问该对象,则它的内存可以是回收。

可以做的是确保没有任何东西是引用你不再使用的内存,因为被引用的内存不能被释放。几乎所有时间,这都是自动发生的。例如:

function foo() {
   var a = [1, 2, 3, 4, 5, 6];

   // Do something
}

分配给数组a 指向的内存有资格在foo 返回后被回收,因为它不再被任何东西引用(a 已经超出范围而没有任何突出的引用) .

相比之下:

function foo() {
   var a = [1, 2, 3, 4, 5, 6];

   document.getElementById("foo").addEventListener("click", function() {
       alert("a.length is " + a.length);
   });
}

现在,a 指向的内存无法回收,因为有一个闭包(事件处理函数)对其有活动引用,并且有一些东西将闭包保存在内存中(DOM 元素)。

您可能认为只有在上述情况下才重要,闭包清楚地使用a,但在这里不重要:

function foo() {
   var a = [1, 2, 3, 4, 5, 6];

   document.getElementById("foo").addEventListener("click", function() {
       alert("You clicked foo!");
   });
}

但是,根据规范 a 被保留,即使闭包不使用它,闭包仍然有对它的间接引用。 (更多内容请参阅我的 [相当老的] 博客文章 Closures Are Not Complicated。)有时 JavaScript 引擎可以优化 a,尽管早期的积极努力被回滚了 - 至少在 V8 中 - 因为执行此操作所需的分析对性能的影响比仅将数组保留在内存中所做的影响更大。

如果我知道闭包不会使用该数组,我可以通过为 a 分配不同的值来确保该数组不被引用:

function foo() {
   var a = [1, 2, 3, 4, 5, 6];

   document.getElementById("foo").addEventListener("click", function() {
       alert("You clicked foo!");
   });

   a = undefined; // <===============
}

现在,虽然a(变量)仍然存在,但它不再引用数组,所以可以回收数组的内存。

更多内容请关注this other answer here on StackOverflow


更新:我可能应该提到delete,尽管它不适用于您问题中的确切代码。

如果您习惯了其他一些语言,您可能会认为“啊,deletenew 的对应物”,但实际上两者完全彼此无关.

delete 用于从对象中删除属性。它不适用于您的代码示例,原因很简单,您无法删除vars。但这并不意味着它与您可能遇到的其他代码无关。

让我们考虑两段似乎在很大程度上做同样事情的代码:

var a = {};         // {} is the same as new Object()
a.prop = "foo";     // Now `a` has a property called `prop`, with the value "foo"
a.prop = undefined; // Now `a` has a property called `prop`, with the value `undefined`

对比

var b = {};         // Another blank object
b.prop = "foo";     // Now `b` has a property called `prop`, with the value "foo"
delete b.prop;      // Now `b` has *NO* property called `prop`, at all

这两者都使prop 指向的内存符合垃圾回收条件,但有区别:在第一个示例中,我们没有删除该属性,但我们已将其值设置为undefined .在第二个示例中,我们从对象中完全删除了该属性。这不是没有区别的区别:

alert("prop" in a); // "true"
alert("prop" in b); // "false"

但这适用于您的问题,因为删除属性意味着该属性指向的任何内存都可用于回收。

那么为什么delete 不适用于您的代码?因为你的person 是:

var person;

var 声明的变量 对象的属性,但它们不能是deleted。 (“它们是对象的属性?”我听到你说。是的。如果你在全局范围内有一个 var,它就会成为全局对象的一个​​属性 [window,在浏览器中]。如果你有一个var 在函数范围内,它成为一个不可见但非常真实的对象的属性,称为“变量对象”,用于调用该函数。无论如何,你不能删除它们。更多关于the link above 中关于闭包的内容。)

【讨论】:

  • +1 用于指出范围链和隐藏的“绑定”。我想知道是否有任何 JS 引擎足够聪明,可以自动消除上述情况——无论如何,只有嵌套范围内的“eval”或显式使用才能访问绑定(从代码)。
  • 感谢您的帮助。将“a = null;”和“a = undefined;”一样吗?
  • @pion: 将“a = null;”和“a = undefined;”做同样的事情?为了释放a 指向的任何其他内存,是的。我使用undefined,因为这是属性(和变量)未初始化时的值,所以我认为undefined(而不是null)是属性的“空白”状态。但是null 也很好,你会看到它被大量使用。 :-)
  • @pst: “我想知道是否有任何 JS 引擎足够聪明,可以自动消除上述情况” 如果 V8 还没有使用没有参考或其中的eval(或者更好的是,使用严格的代码),我敢打赌它会在某个时候。或者如果它没有,你敢打赌我们没有看到一个很好的理由。 :-)
【解决方案2】:

JavaScript 会为您完成这一切,但如果您想显式释放一个对象或变量,那么可以,将其设置为 null 是您可以做到的最接近的方式。

【讨论】:

  • @Phrogz,你不能删除变量,只能删除属性。尝试运行它(在页面中的脚本中,而不是在你的 Firebug/WebKit 控制台中):var a='test',b={c:'test'};console.log('a:',a);console.log('delete a:',delete a);console.log('a:', a);console.log('b.c:',b.c);console.log('delete b.c:',delete b.c);console.log('b.c:',b.c); 然后阅读:perfectionkills.com/understanding-delete
  • Phah。我确定你不能删除变量,然后我看到了另一个建议它的答案,我很懒,只在控制台中测试了它。多么尴尬。 :) 如果计时器没有到,我会编辑我的谎言,所以我会直接删除评论。感谢您对错误信息保持警惕。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-26
  • 2016-04-06
  • 2011-11-18
  • 2011-07-15
  • 2015-09-25
  • 2012-09-17
相关资源
最近更新 更多