局部变量和GC

时间:2012-11-30 06:28:34

标签: javascript garbage-collection

我正试图在Javascript,临时变量和GC中包围私有变量。但是,我无法弄清楚在以下情况会发生什么:

MyClass = function() {
   this.myProp = new createjs.Shape();

   var tempVar = this.myProp.graphics;
   tempVar.rect(0, 0, 10, 100);
   tempVar = null;

   var isDisposed = false;
   this.dispose = function() {
      if (isDisposed) return;
      isDisposed = true;
   }
}
var anInstance = new myClass();

我的目的是让 isDisposed 代表一个私有状态变量, tempVar 是一个use-and-throw变量。

tempVar 是否会标记为GC?是否会将 isDisposed 标记为GC?当我试图声明一个用于处理的临时变量时,以及当我试图在对象中有一个私有变量时,GC如何知道?

我尝试在Chrome中测试以下内容,只要myClass的实例存在,似乎 tempVar 就不会获得GC编辑。所以我不确定现在该相信什么。我不相信我为临时使用而创建的每个局部变量都将存在于对象生命周期的范围内。

1 个答案:

答案 0 :(得分:3)

Javascript没有强类型对象。通过将tempVar设置为null,您并未声明您不想再使用它或将其标记为收集,如Java或C#,您只需将其指定为(完全有效)价值。这是一个开始思考的陷阱,因为你让tempVar变成了一个"实例"一个对象,该变量实际上是一个对象,并且可以在其整个生命周期中对其进行处理。

基本上,变量只是Javascript中的变量。它们可以包含任何东西在这方面它就像VB或VBScript。在许多情况下,标量确实经历过拳击(如在'a|c'.split('|')中将字符串变成字符串)但在大多数情况下,请忘记这一点。函数是第一类对象,这意味着您可以将它们分配给变量,从函数返回它们,将它们作为参数传递,等等。

现在,要实际销毁Javascript中的某些内容,您要么删除对它的所有引用(如对象的情况),要么在对象的属性中,您可以删除它们:< / p>

delete obj.propertyname;
// or //
delete obj[varContainingPropertyName];

为了扩展这一点,以下两个代码段实现了相同的结果:

function abc() {window.alert('blah');}
var abc = function() {window.alert('blah');}

两者都创建一个名为abc的局部变量,该变量恰好是一个函数。第一个可以被认为是第二个的捷径。

但是,根据你引起我注意的this excellent article on deleting,你不能删除局部变量(包括函数,它们实际上也是局部变量)。有异常(如果变量是使用eval创建的,或者它在全局范围内,并且您没有使用IE&lt; = 8,或者您正在使用IE&lt; = 8并且变量已创建在全局范围内,隐含地在x = 1中,这在技术上是一个巨大的错误),所以请阅读文章以获取有关delete的详细信息。

可能对您有用的另一个关键事项是知道在Javascript中只有函数具有范围(以及浏览器实现中的window或其他实现中的全局范围)。 { }中包含的非功能对象和代码块没有范围(我这样说是因为Function的原型是Object,所以函数也是对象,但是特殊的)。这意味着,例如,考虑以下代码:

function doSomething(x) {
   if (x > 0) {
      var y = 1;
   }
   return y;
 }

当使用1执行时,这将返回x > 0,因为变量y的范围是函数,而不是。所以实际上将var声明放在块中是错误和误导的,因为它实际上(尽管可能不是真正的练习)被提升到函数范围。

你应该在javascript中阅读closures(我无法保证该链接的质量)。这样做可能会有所帮助。只要在任何地方维护变量的函数作用域,那么所有函数的私有变量也是如此。您可以做的最好的事情是将它们设置为undefined(更多&#34;没有&#34;比#34; null&#34;在Javascript中)将释放他们拥有的任何对象引用,但是没有真正解除分配变量以使其可用于GC。

对于一般的GCing陷阱,请注意,如果一个函数在DOM元素上有一个闭包,并且某个地方的DOM元素也引用该函数,那么在卸载页面或打破循环引用之前,它们都不会被GC。在某些 - 或所有? - 版本的IE中,这样的循环引用会导致内存泄漏,并且在浏览器关闭之前永远不会进行GC。

尝试更直接地回答您的问题:

  • tempVar将不会被标记为GC,直到它所属的函数释放了所有引用,因为它是一个局部变量,并且Javascript中的局部变量无法删除。
  • isDisposed具有与tempVar相同的品质。
  • Javascript中没有区别&#34;用于处置的临时变量&#34;。在较新版本的ECMAScript中,可以使用实际的getter和setter来定义函数的公共(或私有?)属性。
  • 浏览器控制台可能会为您提供误导性结果,如有关使用Firefox删除的文章中所述。
  • 尽管可能令人难以置信,但在Javascript中,只要变量存在于闭包中,该变量就会保持实例化。这通常不是问题,我没有经历过浏览器真正耗尽内存,因为非垃圾收集周围的微小变量。完成后将变量设置为undefined,并放心 - 我真诚地怀疑您是否会遇到问题。如果您担心,则声明一个本地对象var tmpObj = {tempVar: 'something'};,完成后可以发出delete tmpObj.tempVar;。但在我看来,这将不必要地混乱你的代码。

基本上,我的建议是要理解,在来自其他编程语言时,您已经预先考虑了编程语言应该如何工作的概念。其中一些概念可能在理想的编程语言方面具有有效性。但是,如果放弃这些概念并且至少就目前Javascript的实际工作方式而言,它可能是最好的。直到你真正有足够的经验来自信地违反那些在你之前的人的建议(比如我),你就会冒更大的风险在你的Javascript代码中引入有害的反模式,而不是你可能会纠正任何语言严重不足。没有Dispose()的东西可能是一个非常好的消息 - 它是Javascript根本不需要你的这个令人讨厌的普遍任务,所以你可以花更多的时间来编写功能,花更少的时间来管理它的生命周期。变量。赢了!

我希望你能像我们的意思那样善待我的话。我绝不认为自己是Javascript专家 - 只是我有一些经验和坚实的能力来理解如何使用它以及陷阱是什么。

感谢收听!