Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala中闭包的内存管理是如何工作的?_Scala_Memory Management_Closures - Fatal编程技术网

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

Scala中闭包的内存管理是如何工作的?,scala,memory-management,closures,Scala,Memory Management,Closures,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

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
scala>val counter 1=newCounter
计数器1:()=>Int=
scala>counter1()
res0:Int=1
scala>counter1()
res1:Int=2
scala>val counter 2=newCounter
计数器2:()=>Int=
scala>counter2()
res2:Int=1
scala>counter1()
res3:Int=3
这非常令人印象深刻,因为通常
a
是newCounter堆栈帧上内存地址的代表。我刚刚阅读了“Scala编程”的结尾一章,关于这个问题,它只有以下几点要说(第155页):

Scala编译器在这种情况下会重新安排一些事情,以便捕获的参数存在于堆上,而不是堆栈上,因此可以比创建它的方法调用更有效。这种重新安排是自动完成的,所以你不必担心


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

您可以使用
scalac-Xprint:lambdalift
来研究这一点

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

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
都有一个包装器。其他
变量
(未在闭包中使用)是常见的区域设置变量

指向此包装器的链接作为字段存储在函数实例中


中的
lambdalift
-Xprint:lambdalift
是最简单的。您可以使用
-Xshow phases
获取所有阶段。您可以使用阶段编号而不是名称,这在您不确定需要哪个阶段时非常有用。

cmd行中的“20”是什么意思?顺便说一句,将其与闭包中未使用的另一个外部变量进行对比会很有趣。@pedrofurla:我已更新了我的答案
20
太过分了,
lambdalift
15
)就足够了。@pedrofurla:
命令行中的“20”是什么意思?
。。。这是一个有趣的方法。我不是在建议改进,我是在问。我真的不太在乎这些规则……这就是所谓的“funarg问题”,我猜wiki可能有一些关于道德背景的提示:。一般的解决方案似乎是“将激活记录或其部分放在堆上”。(谷歌可能也能找到一些关于这方面的演讲幻灯片/笔记或论文。)注SIP21“孢子”(whatta名称!)相关问题: