当使用toStream时,是否有资格获得垃圾收集的中间列表?

时间:2014-09-18 03:52:14

标签: scala stream garbage-collection

我想说我要创建一个List[(Int, Int)]

scala> (0 to 3).toList.zip(0 to 3)
res3: List[(Int, Int)] = List((0,0), (1,1), (2,2), (3,3))

但是,如果我想创建一个Stream[(Int, Int)],那该怎么办:

scala> (0 to 3).toList.zip(0 to 3).toStream
res4: scala.collection.immutable.Stream[(Int, Int)] = Stream((0,0), ?)

用于构建res4的中间列表是否有资格进行垃圾回收?

1 个答案:

答案 0 :(得分:1)

如果将列表视为包含列表' s head + link to the tail的对象,则答案是肯定的。

根据消息来源,在创建的流中没有输入列表的闭包,因此可以收集此列表(实际上只是" ::"案例类)。但是列表的尾部(" ::"' s的剩余链)被捕获在闭包内(var tlGen),直到你在流上迭代。

override def toStream : Stream[A] =
    if (isEmpty) Stream.Empty
    else new Stream.Cons(head, tail.toStream)

final class Cons[+A](hd: A, tl: => Stream[A]) extends Stream[A] {
    override def isEmpty = false
    override def head = hd
    @volatile private[this] var tlVal: Stream[A] = _
    @volatile private[this] var tlGen = tl _
    def tailDefined: Boolean = tlGen eq null
    override def tail: Stream[A] = {
      if (!tailDefined)
        synchronized {
          if (!tailDefined) {
            tlVal = tlGen()
            tlGen = null
          }
        }

      tlVal
    }
}

https://github.com/scala/scala/blob/2.11.x/src/library/scala/collection/immutable/List.scala https://github.com/scala/scala/blob/2.11.x/src/library/scala/collection/immutable/Stream.scala#L1223

因此,当流完全迭代时,所有尾部都有资格进行收集。

例如,让我们选择List(1,2,3,4).toStream.foreach(_ => {}):

stream iteration    captured tail     generated stream        eligible for GC
0                   List(2, 3, 4)     Stream(1, ?)            List(1, 2, 3, 4)
1                   List(3, 4)        Stream(1, 2, ?)         List(2, 3, 4)
2                   List(4)           Stream(1, 2, 3, ?)      List(3, 4)
3                   Nil               Stream(1, 2, 3, 4)      List(4)