繁体   English   中英

Scala中的闭包内存管理如何工作?

[英]How does the memory management of closures in Scala work?

Scala允许关闭

def newCounter = {
  var a=0
  () => {a+=1;a}
}

它定义了一个函数,在每次调用时返回一个从1开始的新的独立计数器函数:

scala> val counter1 = newCounter
counter1: () => Int = <function0>

scala> counter1()
res0: Int = 1

scala> counter1()
res1: Int = 2

scala> val counter2 = newCounter
counter2: () => Int = <function0>

scala> counter2()
res2: Int = 1

scala> counter1()
res3: Int = 3

这是非常令人印象深刻的,因为通常a newCounter的堆栈帧上的内存地址的代表。 我刚刚阅读了“Scala编程”的封闭章节,并且在此事上只有以下内容(第155页):

Scala编译器在这种情况下重新排列事物,以便捕获的参数在堆上而不是堆栈中存在,因此可以比创建它的方法调用更长。 这种重新安排都是自动完成的,因此您不必担心。

任何人都可以详细说明它如何在字节码级别上工作? 访问是否类似于具有所有相关同步和性能影响的类的成员变量?

您可以使用scalac -Xprint:lambdalift <scala-file-name>来调查此问题。

你的代码实际上是这样的:

def newCounter = {
  val a: runtime.IntRef = new runtime.IntRef(0);
  new Function0 {
    private[this] val a$1 = a
    def apply() = {
      a$1.elem = a$1.elem + 1
      a$1.elem
    }
  }
}

lambda使用的任何var都有一个包装器。 其他vars (未在闭包中使用)是常见的语言环境变量。

此包装器的链接存储在函数实例中的字段中。

lambdalift in -Xprint:lambdalift编译阶段 您可以使用-Xshow-phases获得所有-Xshow-phases 您可以使用阶段编号而不是名称,当您不确定需要哪个阶段时,它很有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM