2012-06-08 2 views
4

Я пытаюсь создать последовательность, которая соответствует широкому поиску очень широкого, глубокого дерева ... и я сталкиваюсь с проблемами памяти, когда я слишком далеко иду по последовательности. Спросив на канале IRC и посмотрев здесь, причина № 1 в таких проблемах непреднамеренно удерживается на голове; но я не вижу, где я это делаю.Как я могу избежать нехватки памяти кучи при обработке огромных последовательностей в 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». Я запускаю их из REPL в Eclipse/CounterClockwise, на Macbook Air.

Я довольно новичок в Clojure, поэтому, после того как я избил свою голову против этого в течение дня, я надеюсь, что это что-то тривиальное, о котором я не замечаю. Я понимаю, что смогу увеличить размер кучи, чтобы сделать проблему менее вероятной, но последовательности, которые я в конечном счете хочу обработать, настолько обширны, что я не думаю, что это поможет мне.

Я попытался заменить «взять» (в приведенных выше примерах) на «падение», чтобы избежать удержания головы - это не имеет значения.

+0

насчет вашего варианта памяти виртуальной машины Java? > = Xmx2g? –

+0

Это поможет сделать проблему менее вероятной, но она все равно будет происходить дальше по линии, нет? –

ответ

2

Я пропустил дорун. Проблема, похоже, связана со строкой StringBuilder.

Это работает, если я заменю Get-детей, как показано ниже:

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

Когда реплика пытается распечатать последовательность, она удерживает голову. Общей идиомой было бы дозировать на огромном ленивом seq и печатать один элемент за раз. У меня есть альтернативное решение для этого, которое, кажется, работает - суть заменяет str на conj в списке, а затем вместо того, чтобы напрямую оценивать (принимать 200000 ...), использовать дозу и печать. – Shanmu

+0

Прошу игнорировать мой предыдущий комментарий - я пропустил дорун. С альтернативной реализацией get-children, как описано выше, которая позволяет избежать str, гарантирует, что эта реализация будет полностью ленивой. – Shanmu

+0

Я говорю, что вы ошибаетесь. я удалю свой q, и тогда никто не узнает ... (спасибо за то, что он дошел до этого - интересная проблема и все еще не уверен, что я понимаю, почему исправление исправляет вещи) –

Смежные вопросы