2016-12-02 88 views
4

我試圖this challenge,這需要你編寫一個不斷消耗內存的程序。程序拒絕連續消耗內存

我想這將是容易的,所以我寫了:

(reduce conj [] (range)) 

這基本上從無限範圍爲載體增加數;理論上永遠。

問題是,這會跳到3/4GB的內存,然後停止。 CPU仍然在運行,但它拒絕增長。

我決定從Java的答案偷的想法,並覆蓋finalize創建多個對象的每一個被釋放的時間:

(defrecord A [] 
    Object 
    (finalize [this] (mapv (fn [_] (A.)) (range 5)))) ; Create 5 more 

(mapv (fn [_] (A.)) (range)) 

但這停止點的相同點也在增長。

這是不是爆炸?特別是因爲我使用嚴格的map,它應該保留所有內存不應該?就「知道」而言,我希望它在某個時候打印整個列表,所以它需要堅持一切。另外,如果它在某個時候釋放,不應該重寫finalize方法克服這個問題嗎?

任何人都可以解釋這裏發生了什麼?我在休息時寫了這個,所以我可能會忽略某些東西,但我看不到。它在Intellij/Cursive的REPL中進行了測試。

回答

2

您的JVM bascially花費整個時間垃圾收集。在我的系統默認堆大小的上限是〜8.7GB所以根據這是什麼給你,你的GC將努力保持低於此更早:

java -XX:+PrintFlagsFinal -version | grep HeapSize 

你可以用-Xmx JVM選項來增加這一點。

你的程序實際上會繼續運行並不斷向你的向量添加東西。我建議您啓動帶有選項:XX:+PrintGCDetails的JVM以查看發生了什麼。在您接近堆堆棧限制後,JVM將在幾秒鐘內完成全部GC。請注意,那if the JVM spends too much time for the GC then it will throw and OOM error

一看就知道你還是分配,只是扔在一個(when (zero? (rem x 1e5)) (println x))

java -server -Xmx2g -XX:+PrintGCDetails -cp clojure-1.8.0.jar clojure.main -e '(mapv #(cond-> % (zero? (rem % 1e4)) println) (range))'  
+0

哦,謝謝。我不知道Java的答案是如何工作的(如果有的話)。我想他們會遇到同樣的問題。他們沒有提到改變堆的大小。我想知道在高爾夫球場上是否有必要提及。哦,謝謝你的解釋。 – Carcigenicate