机箱内存副本

时间:2011-02-13 01:27:33

标签: javascript

function myClass()
{
  //lots and lots of vars and code here.

   this.bar = function()
   {
     //do something with the numerous enclosed myClass vars
   }

   this.foo = function()
   {
      alert('Hello'); //don't do anything with the enclosed variables.
   }
}

myClass的每个实例都有自己的bar和foo副本,这就是原型方法使用更少内存的原因。但是,我想更多地了解内部方法的内存使用。

我觉得以下(1)必须是真的。你同意吗?

  1. 不同的myClass实例不仅拥有自己独特的bar副本,而且还必须拥有自己的myClass机箱的不同副本。 (或者bar方法如何在每个实例的基础上保持myClass变量的直接?)
  2. 现在(2)是我真正追求的问题。

    1. 由于内部foo方法在myClass机箱中没有使用任何东西,因此自然的问题是:javascript足够聪明,不能将myClass机箱保留在内存中以供foo使用吗?

3 个答案:

答案 0 :(得分:1)

我有理由确定任何函数都有一个指向整个状态的指针。它是否引用它仍然可以访问它们的任何变量是无关紧要的。

当然你确实发布了bar& amp; foo指向对象的相同“整个状态”。所以它不需要更多的内存。我猜你必须在内部再分配一个指针,这样你就可以指向对象的“整个状态”,但是对于类似的东西进行优化是很愚蠢的。

是否优化它是特定于javascript引擎。一定要读取铬源并找出答案。

我会看看我是否可以为你挖出一些报价。

输入规范中的功能代码:

  

10.4.3输入功能代码执行以下步骤时   控制进入执行上下文   用于包含的功能代码   函数对象F,提供的调用者   thisArg和调用者提供的   argumentsList:

     
      
  1. 如果功能代码是严格代码,请将ThisBinding设置为thisArg。
  2.   
  3. 否则,如果thisArg为null或未定义,则将ThisBinding设置为   全球对象。
  4.   
  5. 否则如果Type(thisArg)不是Object,则将ThisBinding设置为   ToObject(thisArg)。
  6.   
  7. 否则将ThisBinding设置为thisArg。
  8.   
  9. 让localEnv成为调用NewDeclarativeEnvironment的结果   传递[[Scope]]的值   F的内部属性为   论点。
  10.   
  11. 将LexicalEnvironment设置为localEnv。
  12.   
  13. 将VariableEnvironment设置为localEnv。
  14.   

将您的环境跟踪到NewDeclarativeEnvironment。

<强> NewDeclarativeEnvironment

  10.2.2.2 NewDeclarativeEnvironment(E)抽象操作时   调用NewDeclarativeEnvironment   无论是词汇环境还是   null作为参数E以下步骤   执行:

     
      
  1. 让我们成为一个新的词汇环境。
  2.   
  3. 让envRec成为一个包含no的新声明性环境记录   绑定。
  4.   
  5. 将env的环境记录设置为envRec。
  6.   
  7. 将env的外部词法环境参考设置为E.
  8.   
  9. 返回环境
  10.   

这会将您的环境跟踪到E,它是函数Object

[[Scope]]
  

13.2创建函数对象给定指定的可选参数列表   通过FormalParameterList,一个正文   由一个Lexical的FunctionBody指定   Scope指定的环境,和   布尔标志Strict,一个Function对象   构造如下:

     
      
  1. 创建一个新的本机ECMAScript对象,让F成为该对象。
  2.   
  3. 如上所述设置F的[[Get]]除外的所有内部方法   在8.12。
  4.   
  5. 将F的[[Class]]内部属性设置为“Function”。
  6.   
  7. 将F的[[Prototype]]内部属性设置为标准内置属性   指定的函数原型对象   在15.3.3.1中。
  8.   
  9. 按照15.3.5.4中的说明设置F的[[Get]]内部属性。
  10.   
  11. 按照13.2.1中的说明设置F的[[Call]]内部属性。
  12.   
  13. 按照13.2.2中的说明设置F的[[Construct]]内部属性。
  14.   
  15. 按照中所述设置F的[[HasInstance]]内部属性   15.3.5.3。
  16.   
  17. 将F的[[Scope]]内部属性设置为Scope的值。
  18.   
  19. 让名称成为包含从左到右文字或
  20. 的列表   

转出规格只是告诉你已经知道的事情。每个函数都包含Scope。正如另一张海报所提到的那样,在内存管理方面,“优化”某些范围取决于个人实施。

如果你问我,你真的不关心这个,除非你有>百万个这些对象的实例。

规范中的以下块更适用:

  

外部环境参考是   用于建模的逻辑嵌套   词汇环境价值观。外面的   (内部)词汇的引用   环境是对的参考   逻辑上的词汇环境   围绕着内心的词汇   环境。一个外在的词汇   当然,环境可能有它的   拥有外在的词汇环境。一个   词汇环境可以作为   多重内在的外部环境   词汇环境。例如,如果   FunctionDeclaration包含两个   嵌套的FunctionDeclarations然后   每个词的词汇环境   嵌套函数将作为他们的   外部词汇环境词汇   当前执行的环境   周围的功能。

两个嵌套函数对外部Lexical Environment

具有相同的引用

答案 1 :(得分:1)

这完全取决于实施而非语言。朴素的实施将远远超过其他实施。任何答案都适用于例如V8(chrome的JS引擎)可能不适用于Spidermonkey(Firefox)或JScript(IE)等......

根据我的经验(这肯定是GHC处理闭包的方式),函数(内部或外部)的实际代码只存在一次,但必须保留将值映射到值的“环境”关闭(bar),所以不,我不希望JS实现保留MyClass的多个副本,但它将保留其环境的副本至少与this.bar,合理的实现可能意识到实际上不需要任何环境foo实际上并不是一个闭包,因此不需要在调用MyClass时保留环境的副本,但是不要依靠这种行为。

特别是因为JS的eval函数的行为在与eval调用相同的词汇环境中计算字符串,所以很有可能JS实现总是保持周围的词汇环境。

答案 2 :(得分:1)

好吧,让我们问一些实施他们做了什么,我们应该: - )

  • Spidermonkey: Internals-Functions - 同意其他答案。谈谈如何对封闭进行分类。

  • V8: Are Closures Optimized - 非常简洁,但确实提到了“静态优化”。网上的各种文章谈论“隐藏类”,我相信,是V8 GC尝试优化闭包的方式。

  • 可悲的是,那些微薄的链接是我所能找到的。可能需要直接分析引擎源代码以添加更有意义的输入。

所以,是的,不同的引擎时可以实现不同的优化策略。