在Scala中,不可变和可变集和映射如何与垃圾收集进行比较?

时间:2012-10-16 02:59:55

标签: scala garbage-collection immutability mutable

我正在编写一些代码,其中涉及使用“小”(例如,短字符串或简单案例类)对象的集合和映射,同时通过大型结构递归,在每个点添加一个小的(通常为1,有时少数几个对象到集合或地图。看起来似乎使用可变集和映射可以显着提高速度,但我无法定量评估差异。

当我使用不可变数据结构时,Scala的垃圾收集会导致显着减慢是否有意义?使用可变数据结构会解决这个问题吗?

2 个答案:

答案 0 :(得分:5)

Scala不可变集合的效率令人惊讶。主要是因为当结构发生变化时,许多结构会被重用。

但如果你做了很多改变,可变结构可能更适合。实际上,这就是Scala Collection API在内部的许多地方所做的事情:使用可变数据结构来构建新东西,并且只作为最后一步,创建一个不可变的并返回它。

答案 1 :(得分:-1)

Scala Mutable数据结构通过预分配内存来提高效率,而不是不可变数据结构。它们更适合于许多插入物(因此它们是可变的)。看一下函数+ =在默认的可变集合中的实现,一个HashMap,Map扩展:

https://github.com/scala/scala/blob/v2.9.2/src/library/scala/collection/mutable/HashMap.scala#L84

def += (kv: (A, B)): this.type = {
  val e = findEntry(kv._1)
  if (e == null) addEntry(new Entry(kv._1, kv._2))
  else e.value = kv._2
  this
}

HashMap使用HashTable实现一个可变的Map,它定义了addEntry

https://github.com/scala/scala/blob/v2.9.2/src/library/scala/collection/mutable/HashTable.scala#L117

protected def addEntry(e: Entry) {
  val h = index(elemHashCode(e.key))
  e.next = table(h).asInstanceOf[Entry]
  table(h) = e
  tableSize = tableSize + 1
  nnSizeMapAdd(h)
  if (tableSize > threshold)
    resize(2 * table.length)
} 

每次达到阈值时,集合的大小会加倍。因此,如果您反复向一个空的可变数据结构添加n个一个条目,则只需要调整log(n)次。我没有深入研究不可变数据结构实现,但我假设您将不得不在每个插入上调整大小。因此,你的表现差异。