@Michał Marczyk 的回答虽然正确,但有点难以理解。我发现Google Groups 上的这篇文章更容易掌握。
我是这样理解的:
第 1 步创建惰性序列:(range 1e8)
. 值尚未实现,我将它们标记为星号 ( *
):
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ... * * *
步骤 2创建另外两个惰性序列,它们是“窗口”,您可以通过它们查看原始的巨大惰性序列。第一个窗口仅包含 12 个元素 ( t
),另一个是其余元素 ( d
):
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ... * * *
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
第 3 步 - 内存不足场景- 您评估[(count d) (count t)]
。因此,首先计算 中的元素d
,然后计算 中的元素t
。将会发生的是,您将从 的第一个元素开始遍历所有值d
并实现它们(标记为!
):
* * * * * * * * * * * * * ! * * * * * * * * * * * * * * * * ... * * *
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
^
start here and move right ->
* * * * * * * * * * * * * ! ! * * * * * * * * * * * * * * * ... * * *
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
^
* * * * * * * * * * * * * ! ! ! * * * * * * * * * * * * * * ... * * *
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
^
...
; this is theoretical end of counting process which will never happen
; because of OutOfMemoryError
* * * * * * * * * * * * * ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ... ! ! !
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
^
问题是所有已实现的值 ( !
) 都被保留了,因为仍然需要集合的头部(前 12 个元素)——我们仍然需要评估(count t)
。这会消耗大量内存,导致 JVM 崩溃。
第 3 步 - 有效场景- 这次您进行评估[(count t) (count d)]
。所以我们首先要计算较小的头部序列中的元素:
! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ... * * *
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
^
start here and move right ->
! * * * * * * * * * * * * * * * * * ... * * *
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
^
d
然后,我们按顺序计算元素。编译器知道t
不再需要来自的元素,因此它可以垃圾收集它们以释放内存:
! * * * * * * * * * * * * * * * * ... * * *
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
^
! * * * * * * * * * * * * * * * ... * * *
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
^
...
... !
t t t t t t t t t t t t t d d d d d d d d d d d d d d d d d ... d d d
^
现在我们可以看到,因为t
不再需要 from 的元素,编译器能够在经过大序列时清除内存。