I was expecting extremely small increase in memory usage after adding an element to immutable Seq. Because new reference (val) can re-use memory allocate for already created val and an additional memory allocation would be required for the new element only. In other words I do not see a necessity for the defensive copy to be created (see here https://users.scala-lang.org/t/inquiry-on-immutabillity-of-objects-and-how-they-affect-memory/2340).
In reality, however, after adding one element memory usage increases to the same amount as creating completely new Seq. Below is a code snippet from the SBT project
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))
}
In the output we see that memory usage after step 2 and after step 4 increased by almost 24MB. I would expect very small increase after step 4 though.
1 4103816
2 23948288
3 4546184
4 23948600
Can someone explain this behaviour? Or alternatively how to see that memory is re-used for immutable objects.
Also I was quite surprised that memory usage for ArrayBuffer is much smaller than for Seq (4MB vs 24MB). Would be great to understand this difference as well.