在Scala中管理未使用的`List`s

时间:2011-11-30 18:25:51

标签: scala garbage-collection

Scala拥有丰富的不可变结构。

我想知道Scala如何管理这些对象的过度分配和释放。如何查找现有的子列表,例如将1连接到List(1,2,3)。如何跟踪某个List未被使用,并允许垃圾收集器释放它?

我会像这样设计它

class List {
    private Map<Integer,WeakRef<List>> listCache;
    public List(Integer head,List tail) {...}
    public synchronized List prepend(Integer i) {
        if (listCache.get(i) != null) {
            if (listCache.get(i).get() == null) {
                listCache.put(i,new List(i,this));
            }
    }
}

Scala如何设计?它是否能很好地处理过多的分配和解除分配?它对线程有什么作用?

2 个答案:

答案 0 :(得分:3)

让我们写一个简单的List类:

sealed abstract class MyList[+T] {
  def head: T
  def tail: MyList[T]
  def isEmpty: Boolean
  def prepend[T1 >: T](el: T1): MyList[T1]
}

object EmptyList extends MyList[Nothing] {
  def head: Nothing = throw new java.util.NoSuchElementException("head of an empty list")
  def tail: MyList[Nothing] = throw new UnsupportedOperationException("unsupported operation exception")
  def isEmpty = true
  def prepend[T1 >: Nothing](el: T1): MyList[T1] = new Cons(el, this)

  override def toString = "EmptyList"
}

final class Cons[+T](val head: T, val tail: MyList[T]) extends MyList[T] {
  def isEmpty = false
  def prepend[T1 >: T](el: T1): MyList[T1] = new Cons(el, this)

  override def toString = head + ", " + tail.toString
}

Scala中的列表就是这样的。那么,考虑一下你提到的例子:

scala> val list = new Cons(1, new Cons(2, new Cons(3, EmptyList)))
list: Cons[Int] = 1, 2, 3, EmptyList

scala> val newList = list.prepend(1)
newList: MyList[Int] = 1, 1, 2, 3, EmptyList

所以,问题:

  • 我们是否查找了重复使用的列表?否。
  • 我们重用了什么吗?是的,我们重用了prepend被调用的列表。
  • 如何收集垃圾?就像JVM中的任何对象一样:当没有任何对象指向它时,它将被收集。

当然,如果我创建另一个这样的列表:

val list2 = list.prepend(1)

然后newListlist2将共享list,但即使它们包含相同的元素,也会是不同的列表。

你可能会质疑(正如在评论中所做的那样)这种可重用性模式是否切实可行,或者它是否会带来现实生活中的任何收益,而答案就是 lot 算法利用它。

事实上,让我指出this question,其中所谓的“慢”代码实际上比所谓的“快速”代码以及答案中建议的替代代码更快。 原因为什么“慢”代码无关紧要就是这种重用模式。

答案 1 :(得分:1)

Scala根本不管理这些对象的重新分配。它们作为普通的JVM对象在堆上创建,并且由JVM收集的垃圾就像任何其他Java或Scala对象一样。正如您对问题的评论所指出的那样,它不会重复使用从之前调用List()创建的列表 - 它始终是一个新对象。

通过连接列表澄清情况 - 在这种情况下,生成的List对象 保持对列表两端的引用,但它仍然没有执行任何特殊的缓存使用过的清单或类似的东西。