Почему буфер итератора Scala Range - иногда? - PullRequest
4 голосов
/ 23 ноября 2011

В 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 ]

8 голосов
/ 23 ноября 2011

toIterator определяется в TraversableLike как

def toIterator: Iterator[A] = toStream.iterator

, поэтому он создает Stream в фоновом режиме, который сохраняет все элементы в памяти во время итерации.

( Редактировать : Я думаю, что структура потока здесь не является проблемой на самом деле. Однако, toStream сам вызывает toBuffer, который, в свою очередь, копирует каждое отдельное значение.)

iterator, с другой стороны, определен в IndexedSeqLike, в котором используется специализированная структура, не сохраняющая никаких элементов в памяти.

2 голосов
/ 23 ноября 2011

Если вы присмотритесь к коду, то как все определено.

Когда вы вызываете toIterator, он берет все в последовательности и копирует его в ArrayBuffer (сначала пытаясь преобразовать его в поток.) ​​Вероятно, эта копия приводит к тому, что вам не хватает памяти.

Когда вы используете итератор, он создает экземпляр защищенного класса Elements, который возвращает BufferedIterator. Он использует сам класс для возврата элементов.

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

        val x = self(index)
        index += 1

        x
     }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...