簡體   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