Scala中的闭包的内存管理如何工作? [英] How does the memory management of closures in Scala work?

查看:95
本文介绍了Scala中的闭包的内存管理如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Scala允许像这样

Scala allows closure like

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

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

which defines a function that on every call returns a new independent counter function starting at 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页):

This is quite impressive as usually a would be a representative of a memory address on the stack frame of newCounter. I've just read the closure chapter of "Programming in Scala" and it only has the following to say on that matter (p. 155):

在这样的情况下,Scala编译器会重新安排事情,以便捕获的参数在堆(而不是堆栈)中有效,从而使创建它的方法调用的寿命更长.重新安排都会自动处理,因此您不必担心.

The Scala compiler rearranges things in cases like this so that the captured parameter lives out on the heap, instead of the stack, and thus can outlive the method call that created it. This rearrangement is all taken care of automatically, so you don't have to worry about it.

谁能详细说明它在字节码级别上如何工作?访问是否类似于具有所有相关联的同步和性能含义的类的成员变量?

Can anyone elaborate on how this works on byte code level? Is the access similar to a member variable of a class with all the associated synchronization and performance implications?

推荐答案

您可以使用scalac -Xprint:lambdalift <scala-file-name>对此进行调查.

You could use scalac -Xprint:lambdalift <scala-file-name> to investigate this.

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

Your code is actually something like this:

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(未在闭包中使用)是常见的语言环境变量.

There is a wrapper for any var used by lambda. Other vars (not used in closures) are common locale variables.

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

The link to this wrapper is stored as field in the instance of function.

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

lambdalift in -Xprint:lambdalift is the compiler phase. You can get all phases with -Xshow-phases. You could use phase number instead of name, it's useful when you are not sure which phase you need.

这篇关于Scala中的闭包的内存管理如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆