2012-06-08 35 views
4

我試圖生成一個序列,它對應於廣泛深度樹的廣度優先搜索......當我沿着序列走得太遠時,我遇到了內存問題。在問及IRC頻道並看了這裏之後,導致這些問題的頭號原因是無意中捂住了腦袋;但我看不到我在做什麼。在Clojure中處理大量序列時,如何避免用盡堆內存?

該代碼非常簡單;這裏是其中顯示了問題的一個版本:

(def atoms '(a b c)) 

(defn get-ch [n] (map #(str n %) atoms)) 

(defn add-ch 
    ([] (apply concat (iterate add-ch atoms))) 
    ([n] (mapcat get-ch n))) 

(dorun (take 20000000 (add-ch))) 

而這裏的另一個版本(這是我正從#clojure幫助之前,開始了以一個),它顯示了同樣的問題:

(def atoms '(a b c)) 

(defn get-children [n] (map #(str n %) atoms)) 

(defn add-layer 
    ([] (add-layer atoms)) 
    ([n] (let [child-nodes (mapcat get-children n) ] 
     (lazy-seq (concat n (add-layer child-nodes)))))) 

(dorun (take 20000000 (add-layer))) 

兩個給我一個「OutOfMemoryError Java堆空間」。我使用Eclipse/CounterClockwise中的REPL在Macbook Air上運行它們。

我對Clojure非常陌生,所以在打了一天我的頭後,我希望這是我忽略的一些小事。我意識到我可以提高堆大小以減少問題的發生,但是我最終想要處理的序列非常龐大,我認爲這不會對我有幫助。

我試過用「drop」替換「take」(在上面的例子中),以避免保持頭部 - 它沒有區別。

+0

那你的JVM的內存選項? > = Xmx2g? –

+0

這有助於減少問題發生的可能性,但它仍然會發生在更遠的地方,不是嗎? –

回答

2

我錯過了寢室。 這個問題似乎與StringBuilder str有關。

這工作,如果我取代得到子女如下:

(defn get-children [n] (map #(if (seq? n) (conj n %) (conj (list n) %)) atoms)) 
+0

當repl嘗試打印序列時,它保持頭部不動。一個常見的習慣用法是在大量的懶惰seq上打印一次,然後打印一個元素。我有一個替代解決方案,這似乎工作 - 的要點是用列表中的連接符替換str,然後直接評估(採取200000 ...),使用doseq和print。 – Shanmu

+0

請忽略我之前的評論 - 我錯過了dorun。如上所述的get-children的替代實現避免了str,從而確保此實現始終是懶惰的。 – Shanmu

+0

我說刪除錯誤的東西。我會刪除我的q,然後沒有人會知道...(感謝收到他的底部 - 有趣的問題,仍然不知道我明白爲什麼修復修復的東西) –

相關問題