2012-08-13 29 views
2

當在工作中對一些Clojure代碼進行壓力測試時,我發現在迭代大型數據集時,堆空間耗盡。我最終設法將這些問題追溯到Clojure的doseq函數的組合,以及對懶惰序列的實現。doseq通過一個簡單的懶惰seq耗盡堆空間

這是最少的代碼片段,通過耗盡可用堆空間崩潰的Clojure:

(doseq [e (take 1000000000 (iterate inc 1))] (identity e)) 

doseq的文件明確指出它不保留偷懶序列的頭,所以我期望上述代碼的內存複雜度接近O(1)。有什麼我失蹤?如果doseq不能勝任這項工作,那麼循環遍歷極大的惰性序列的Clojure慣用方法是什麼?

+7

Clojure的哪個版本和Java運行時您正在使用?在OSX上使用clojure 1.4/java 1.6.0_33在乾淨的repl中運行該代碼,顯示完全靜態內存使用率低於400 Mb – 2012-08-13 11:42:23

+1

您確定這是導致問題的確切代碼段嗎?在我的機器上運行良好(Clojure 1.4,JDK7,Windows,Eclipse/CCW)。如果你以某種方式保持在序列的頭部,它將*成爲一個問題,例如,如果(iterate inc 1)存儲在其他地方。 – mikera 2012-08-14 02:13:56

+0

你是對的,當我關閉Leiningen 2給REPL(歷史,關鍵導航等)添加的東西並且使用香草Clojure 1.4時,問題就消失了。謝謝。 – the80srobot 2012-08-14 08:07:13

回答

2

當我運行這個示例時,我看到內存使用量達到2.0 Gigs,所以您可能實際上只是用完了內存。

它肯定也需要一段時間來運行:

user=> (time (doseq [e (take 1000000000 (iterate inc 1))] (identity e))) 
"Elapsed time: 266396.221132 msecs" 

形式頂部:

23999 arthur 20 0 4001m 1.2g 5932 S 213 15.3 17:11.35 java           
24017 arthur 20 0 3721m 740m 5548 S 88 9.3 13:49.95 java