回答@MichałMarczyk,雖然正確,但有點難以理解。我發現this post on Google Groups更容易掌握。
我是這樣理解的:
步驟1創建懶序列:(range 1e8)
。值尚無法實現,我將其標示爲asterixes(*
):
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ... * * *
步驟2創建兩個懶seqences這是「窗口」,通過它,你看原來,巨大的懶序列。第一個窗口只含有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
元素,編譯器能夠清晰的記憶,因爲它經歷了大的序列。
你說「本地T需要流連第二個電話來算,並且由於它發生在一個巨大的序列,這導致OOME點。」但't'只是12項順序。 如何處置't'扮演這樣一個巨大的作用,如果它是12個項目序列。而拿着'D'內存心不是一個問題,但它是'(範圍1E8)' –
好了,'噸其餘全部'在以某種方式使用之前是一個未實現的懶惰seq,它在內部持有一些代碼,在某些時候可能需要實現't'。這段代碼需要在傳遞給'split-with'的原始序列中保存一個指針,所以它可以將它傳遞給'take-while'(參見'split-with'的實現)。感謝您的評論 - 這應該是答案,我會在編輯的一部分 –
所以你說的話是,'t'舉行,它擁有實際內存中的整個原始序列? 因此,雖然'(count d)'正在計算,與我們clojure並行,保持整個原始序列在內存中實現? –