为什么Scala Range迭代器缓冲区 - 有时?

时间:2011-11-23 15:19:06

标签: scala memory iterator

在Scala 2.9.1中,这很好用:

scala> (1 to Int.MaxValue).sum
res6: Int = -1073741824

然而这用完了堆空间:

scala> (1 to Int.MaxValue).toIterator.sum
java.lang.OutOfMemoryError: GC overhead limit exceeded

但令人抓狂的是,这有效:

scala> (1 to Int.MaxValue).iterator.sum
res8: Int = -1073741824

为什么其中任何一个都不同?

2 个答案:

答案 0 :(得分:8)

toIteratorTraversableLike中定义为

def toIterator: Iterator[A] = toStream.iterator

所以它在后台创建一个Stream,在迭代时将所有元素保存在内存中。

编辑:我认为实际上流结构不是问题。但是,toStream本身会调用toBuffer,而iterator会复制每一个值。)< / p> 另一方面,

IndexedSeqLike在{{1}}中定义,它使用一种不会在内存中保留任何元素的专门结构。

答案 1 :(得分:2)

如果仔细查看代码,就会知道所有内容的定义。

当你调用toIterator时,它会接受序列中的所有内容并将其复制到ArrayBuffer中(首先尝试将其转换为流。)此副本很可能是导致内存不足的原因。

使用迭代器时,它会创建一个返回BufferedIterator的受保护类Elements的实例。这使用类本身来返回元素。

protected class Elements(...) ... {
    ...
    def next: A = {
        if (index >= end)
            Iterator.empty.next

        val x = self(index)
        index += 1

        x
     }
}