2013-08-07 4 views
4

Я пытаюсь разобрать довольно небольшой (< 100MB) XML-файл с:Clojure Leining РЕПЛ OutOfMemoryError Java куча пространства

(require '[clojure.data.xml :as xml] 
     '[clojure.java.io :as io]) 

(xml/parse (io/reader "data/small-sample.xml")) 

и я получаю сообщение об ошибке:

OutOfMemoryError Java heap space 
    clojure.lang.Numbers.byte_array (Numbers.java:1216) 
    clojure.tools.nrepl.bencode/read-bytes (bencode.clj:101) 
    clojure.tools.nrepl.bencode/read-netstring* (bencode.clj:153) 
    clojure.tools.nrepl.bencode/read-token (bencode.clj:244) 
    clojure.tools.nrepl.bencode/read-bencode (bencode.clj:254) 
    clojure.tools.nrepl.bencode/token-seq/fn--3178 (bencode.clj:295) 
    clojure.core/repeatedly/fn--4705 (core.clj:4642) 
    clojure.lang.LazySeq.sval (LazySeq.java:42) 
    clojure.lang.LazySeq.seq (LazySeq.java:60) 
    clojure.lang.RT.seq (RT.java:484) 
    clojure.core/seq (core.clj:133) 
    clojure.core/take-while/fn--4236 (core.clj:2564) 

Вот мой project.clj:

(defproject dats "0.1.0-SNAPSHOT" 
    ... 
    :dependencies [[org.clojure/clojure "1.5.1"] 
       [org.clojure/data.xml "0.0.7"] 
       [criterium "0.4.1"]] 
    :jvm-opts ["-Xmx1g"]) 

Я попытался установить в LEIN_JVM_OPTS и JVM_OPTS в моем .bash_profile без успеха.

Когда я попытался следующий project.clj:

(defproject barber "0.1.0-SNAPSHOT" 
    ... 
    :dependencies [[org.clojure/clojure "1.5.1"] 
       [org.clojure/data.xml "0.0.7"] 
       [criterium "0.4.1"]] 
    :jvm-opts ["-Xms128m"]) 

Я получаю следующее сообщение об ошибке:

Error occurred during initialization of VM 
Incompatible minimum and maximum heap sizes specified 
Exception in thread "Thread-5" clojure.lang.ExceptionInfo: Subprocess failed {:exit-code 1} 

Любая идея, как я могу увеличить размер кучи для моего Leiningen РЕПЛ?

Спасибо.

+0

Сохранение некоторых данных (результат синтаксического анализа XML) в массиве? Если да, то насколько он большой? – Chiron

+0

Вы используете вторую строку из REPL? –

+0

Chiron: Не хранить XML в любой структуре данных. Просто вызывая метод разбора, как в моем посте. Igrapenthin: Да, я вызываю синтаксическую линию из REPL. Файл 50MB, распакованный. –

ответ

3

Любая форма, оцененная на верхнем уровне репликации, полностью реализуется в результате этапа печати Read-Eval-Print-Loop. Он также сохраняется в куче, так что вы можете позже получить доступ к нему через * 1.

если вы храните возвращаемое значение следующим образом:

(def parsed (xml/parse (io/reader "data/small-sample.xml")))

это возвращается немедленно, даже для файла сотни мегабайт (я проверил это на месте). Затем вы можете перебирать результат, который реализуется полностью, поскольку он анализируется из входного потока, итерацией по возвращенному дереву clojure.data.xml.Element.

Если вы не держитесь за элементы (связывая их так, чтобы они все еще были доступны), вы можете выполнять итерацию по всей структуре без использования большего количества бара, чем для хранения единственного узла дерева xml.

user> (time (def n (xml/parse (clojure.java.io/reader "/home/justin/clojure/ok/data.xml")))) 
"Elapsed time: 0.739795 msecs" 
#'user/n 
user> (time (keys n)) 
"Elapsed time: 0.025683 msecs" 
(:tag :attrs :content) 
user> (time (-> n :tag)) 
"Elapsed time: 0.031224 msecs" 
:catalog 
user> (time (-> n :attrs)) 
"Elapsed time: 0.136522 msecs" 
{} 
user> (time (-> n :content first)) 
"Elapsed time: 0.095145 msecs" 
#clojure.data.xml.Element{:tag :book, :attrs {:id "bk101"}, :content (#clojure.data.xml.Element{:tag :author, :attrs {}, :content ("Gambardella, Matthew")} #clojure.data.xml.Element{:tag :title, :attrs {}, :content ("XML Developer's Guide")} #clojure.data.xml.Element{:tag :genre, :attrs {}, :content ("Computer")} #clojure.data.xml.Element{:tag :price, :attrs {}, :content ("44.95")} #clojure.data.xml.Element{:tag :publish_date, :attrs {}, :content ("2000-10-01")} #clojure.data.xml.Element{:tag :description, :attrs {}, :content ("An in-depth look at creating applications \n  with XML.")})} 
user> (time (-> n :content count)) 
"Elapsed time: 48178.512106 msecs" 
459000 
user> (time (-> n :content count)) 
"Elapsed time: 86.931114 msecs" 
459000 
;; redefining n so that we can test the performance without the pre-parsing done when we counted 
user> (time (def n (xml/parse (clojure.java.io/reader "/home/justin/clojure/ok/data.xml")))) 
"Elapsed time: 0.702885 msecs" 
#'user/n 
user> (time (doseq [el (take 100 (drop 100 (-> n :content)))] (println (:tag el)))) 
:book 
:book 
.... ;; output truncated 
"Elapsed time: 26.019374 msecs" 
nil 
user> 

Обратите внимание, что это только тогда, когда я первый просить подсчета содержания п (тем самым принуждая весь файл, который будет обработан), что огромная временная задержка. Если я доживаю до подраздела структуры, это происходит очень быстро.

+0

Спасибо за ответ. Я понимаю точку ленивой оценки, но в моем случае вызов (time (-> n: content count)) также приведет к ошибке java.lang.OutOfMemoryError: Java heap space. В целом, я пытаюсь найти способ получить более 50 МБ кучи, но не могу понять это. –

+0

Сообщение об ошибке «Несовместимые минимальные и максимальные размеры кучи» указывает мне, что где-то установлен низкий максимум, что вам как-то нужно обойти или переопределить. Параметры, которые дали вам эту ошибку, указывали размер начальной кучи (-Xms), но не максимальный размер кучи (-Xmx) – noisesmith

+0

Кроме того, я не знаю, что вы пытаетесь сделать, часто будет некоторый подход к сокращению, который выполняет то, что вы хотите, не требуя сразу всего набора данных в памяти. – noisesmith

2

Я не знаю, о Lein, как много, но в MVN вы можете сделать следующее:

mvn -Dclojure.vmargs="-d64 -Xmx2G" clojure:nrepl 

(я не думаю, что это важно, но я всегда видел его с Капитолия G это чувствительный к регистру?)

Вывод 100 МБ данных в память не должен быть проблемой. Я регулярно маршрутизирую данные по данным GB по моим проектам.

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

JVM options using Leiningen

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

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