2013-12-03 3 views
4

Предположим, у меня есть Stream длины 1,000,000 со всеми 1.Фильтр потока # Испускает память для 1 000 000 предметов

scala> val million = Stream.fill(100000000)(1) 
million: scala.collection.immutable.Stream[Int] = Stream(1, ?) 

scala> million filter (x => x % 2 == 0) 
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded 

Я получаю исключение Out of Memory.

Затем я попробовал тот же filter позвонить с List.

scala> val y = List.fill(1000000)(1) 
y: List[Int] = List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ... 

scala> y.filter(x => x % 2 == 0) 
res2: List[Int] = List() 

Все еще это удается.

Почему у Stream#filter заканчивается память, но List#filter заканчивается просто отлично?

И наконец, с большим потоком, будет filter результат в ленивой оценке всего потока?

+0

Посмотреть это сообщение: http://stackoverflow.com/questions/5159000/stream-vs-views-vs-iterators. Он работает с 'def million = Stream.fill (100000000) (1)' в качестве заметок. – Brian

+0

Я предполагаю, что ячейки, которые содержат индивидуальные значения в потоке, больше в памяти, чем ячейки, которые составляют отдельные элементы в списке. Кроме того, если вы находитесь в Repl, и вы сначала выделили список, а _then_ - поток, вы настраиваете себя на неудачу. – KChaloux

+0

@KChaloux - Нет - моя ошибка scala REPL упала после исключения, поэтому я снова запустил «scala» за один миллионный тест List. В результате исключения я ожидал, что «scala» выпустит свои ресурсы. –

ответ

3

Накладные расходы List - отдельный объект (пример ::) с 2 полями (2 указателя) на элемент.

Накладных Stream - экземпляр Cons (с 3 указателей) плюс экземпляр Function (tl: => Stream[A]) для ленивой оценки Stream#tail на элемент.

Значит, вы потратите ~ 2 раза больше памяти на Stream.

Вы определили свой Stream как val. В качестве альтернативы вы можете определить million как def - в этом случае после filter GC удалит все созданные элементы, и вы вернете свою память.

Обратите внимание, что в Stream только tail лениво, head строго, поэтому filter оценивает строго, пока не получит первый элемент, который удовлетворяет заданный предикат, а так как там нет таких элементов в Streamfilter перебирает все ваш million потока и помещает все элементы в память.

+0

Если я понимаю, 'плюс экземпляр Function (tl: => Stream [A])', то 'Stream # filter' работает ленивым способом, да? –

+0

@KevinMeredith: к сожалению нет. Он оценивает все начальные «потоки». – senia

+0

by 'all initial Stream', это означает, что' million.filter (x => x% 2 == 0) 'будет помещать весь поток в память, а затем оценивать предикат фильтра? –

Смежные вопросы