在向不可變 Seq 添加元素后,我期望記憶體使用量增加極小。因為新參考 ( val) 可以重用已創建val的記憶體分配,并且只需要為新元素分配額外的記憶體。換句話說,我認為沒有必要創建防御性副本(參見此處https://users.scala-lang.org/t/inquiry-on-immutabilility-of-objects-and-how-they-affect -記憶體/2340)。
然而,實際上,在添加一個元素后,記憶體使用量增加到與創建全新 Seq 相同的數量。下面是來自 SBT 專案的代碼片段
object obj extends App {
val n = 1000000
def usedMem = {
val runtime = Runtime.getRuntime
runtime.totalMemory - runtime.freeMemory
}
val m1 = usedMem
val ar = scala.collection.mutable.ArrayBuffer.fill(n)("hohohohoho")
val m2 = usedMem
println ("1 " (m2-m1))
val sq = Seq.fill(n)("hohohohoho")
val m3 = usedMem
println ("2 " (m3-m2))
val ar0 = ar : "yo"
val m4 = usedMem
println ("3 " (m4-m3))
val sq0 = sq : "yo"
val m5 = usedMem
println ("4 " (m5-m4))
}
在輸出中,我們看到第 2 步和第 4 步之后的記憶體使用量增加了近 24MB。不過,我希望在第 4 步之后會有很小的增長。
1 4103816
2 23948288
3 4546184
4 23948600
有人可以解釋這種行為嗎?或者,如何查看記憶體被重用于不可變物件。
我也很驚訝 ArrayBuffer 的記憶體使用量比 Seq 小得多(4MB vs 24MB)。理解這種差異也會很棒。
uj5u.com熱心網友回復:
那是因為您沒有為作業使用正確的資料結構。
這里:val sq = Seq.fill(n)("hohohohoho")您正在創建 aSeq但 aSeq是一個抽象型別,因此它必須選擇一個具體的實作。在撰寫本文時,這種默認值通常是List
并且Lists在追加時不能共享記憶體,他們必須復制所有內容(這意味著它也很慢)。
現在,您可以做的是使用優化為追加的資料結構,例如Vector或貓 Chain
您也可以List直接使用并前置而不是像這樣的追加:
val sq = List.fill(n)("hohohohoho")
val sq0 = "yo" :: sq
這是我個人不喜歡Seq它的原因之一,它沒有提供足夠的資訊來做任何有用的事情。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/327802.html
上一篇:當只有第一個事件發生時,如何考慮第二個事件?[復制]
下一篇:使Spark代碼更高效、更簡潔
