假设我的Stream
长度1,000,000
全部为1。
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 :(得分:3)
List
的开销 - 单个对象(::
的实例),每个元素有2个字段(2个指针)。
Stream
的开销 - Cons
的实例(有3个指针)加上Function
(tl: => Stream[A]
)的实例,用于对每个元素Stream#tail
进行延迟评估
所以你会在Stream
上花费大约2倍的内存。
您已将Stream
定义为val
。或者,您可以将million
定义为def
- 在这种情况下,filter
GC将删除所有创建的元素,然后您将获得回忆。
请注意,只有tail
中的Stream
是惰性的,head
是严格的,所以filter
严格评估,直到它获得满足给定谓词的第一个元素,并且从那里开始您的Stream
filter
迭代所有million
流中没有此类元素,并将所有元素放入内存中。