xml-parsing clojure out-of-memory clojure-java-interop

xml parsing - Clojure Leining REPL OutOfMemoryError Java montón de espacio



xml-parsing out-of-memory (2)

Cualquier formulario evaluado en el nivel superior de la réplica se realiza en su totalidad, como resultado del paso de impresión de Read-Eval-Print-Loop. También se almacena en el montón, para que luego pueda acceder a él a través de * 1.

si almacena el valor de retorno de la siguiente manera:

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

esto regresa inmediatamente, incluso para un archivo de cientos de megabytes de tamaño (lo he verificado a nivel local). A continuación, puede recorrer el resultado, que se realiza en su totalidad a medida que se analiza desde la secuencia de entrada, iterando sobre el árbol clojure.data.xml.Element que se devuelve.

Si no se aferra a los elementos (al vincularlos para que sigan siendo accesibles), puede recorrer la estructura completa sin utilizar más memoria RAM de la que necesita para contener un único nodo del árbol 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>

Tenga en cuenta que solo cuando pido por primera vez el recuento del contenido de n (forzando así el análisis del archivo completo) se produce el enorme retraso. Si administro dosisq en subsecciones de la estructura, esto sucede muy rápidamente.

Estoy tratando de analizar un archivo xml bastante pequeño (<100MB) con:

(require ''[clojure.data.xml :as xml] ''[clojure.java.io :as io]) (xml/parse (io/reader "data/small-sample.xml"))

y recibo un error:

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)

Aquí está mi 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"])

Traté de establecer un LEIN_JVM_OPTS y JVM_OPTS en mi .bash_profile sin éxito.

Cuando probé el siguiente 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"])

Obtuve el siguiente error:

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}

¿Alguna idea de cómo podría aumentar el tamaño del montón para mi Leiningen?

Gracias.


No sé mucho sobre lein pero en mvn puedes hacer lo siguiente:

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

(No creo que importe pero siempre lo he visto con un capitolio G ¿es sensible a mayúsculas y minúsculas?)

Poner 100 MB de datos en la memoria no debería ser un problema. Rutinariamente enrutar el valor de GB de datos a través de mis proyectos.

Siempre uso el servidor de la versión de 64 bits para montones grandes también, y eso parece ser lo que están haciendo aquí:

Opciones de JVM usando Leiningen

Creo que el problema más grande, sin embargo, es que a medida que lo tienes escrito esto podría estar siendo evaluado en tiempo de compilación. Debe ajustar esa llamada en una función y aplazar su ejecución. Creo que el compilador intenta leer ese archivo, y probablemente no sea lo que quieres. Sé con mvn que obtienes diferentes ajustes de memoria para compilar frente a ejecutar y es posible que también lo consigas.