Pertanyaan Clojure Leining REPL OutOfMemoryError ruang tumpukan Java


Saya mencoba mem-parsing file xml yang cukup kecil (<100MB) dengan:

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

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

dan saya mendapatkan kesalahan:

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)

Inilah project.clj saya:

(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"])

Saya mencoba menetapkan LEIN_JVM_OPTS dan JVM_OPTS di .bash_profile saya tidak berhasil.

Ketika saya mencoba proyek berikut.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"])

Saya mendapatkan kesalahan berikut:

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}

Tahu bagaimana saya bisa meningkatkan ukuran tumpukan untuk leiningen saya?

Terima kasih.


4
2017-08-07 03:43


asal


Jawaban:


Setiap bentuk yang dievaluasi pada tingkat atas dari pengulangan direalisasikan secara penuh, sebagai hasil dari langkah cetak dari Read-Eval-Print-Loop. Ini juga disimpan di heap, sehingga nantinya Anda dapat mengaksesnya melalui * 1.

jika Anda menyimpan nilai pengembalian sebagai berikut:

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

ini akan segera kembali, bahkan untuk file berukuran ratusan megabyte (saya telah memverifikasi ini secara lokal). Anda kemudian dapat mengiterasi seluruh hasil, yang direalisasikan secara penuh saat diurai dari aliran masukan, dengan iterasi di atas clojure.data.xml. Pohon pilihan yang dikembalikan.

Jika Anda tidak berpegang pada elemen (dengan mengikat mereka sehingga mereka masih dapat diakses), Anda dapat iterate atas seluruh struktur tanpa menggunakan ram lebih dari yang dibutuhkan untuk memegang satu simpul dari pohon 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> 

Perhatikan bahwa hanya ketika saya pertama kali meminta hitungan konten n (sehingga memaksa seluruh file yang akan diurai) bahwa penundaan waktu besar terjadi. Jika saya dosisq di subbagian struktur, ini terjadi sangat cepat.


3
2017-08-08 16:25



Saya tidak tahu banyak tentang lein tetapi di mvn Anda dapat melakukan hal berikut:

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

(Saya tidak berpikir itu penting tapi saya selalu melihatnya dengan huruf kapital G apakah itu sensitif huruf?)

Menarik 100MB data ke dalam memori seharusnya tidak menjadi masalah. Saya secara rutin mengarahkan data senilai GB melalui proyek-proyek saya.

Saya selalu menggunakan server versi 64bit untuk tumpukan besar juga, dan sepertinya itulah yang mereka lakukan di sini:

Opsi JVM menggunakan Leiningen

Saya pikir masalah yang lebih besar, adalah bahwa seperti yang Anda tulis ini mungkin sedang dievaluasi pada waktu kompilasi. Anda perlu membungkus panggilan itu dalam suatu fungsi, dan menunda eksekusi itu. saya berpikir kompiler sedang mencoba membaca file itu, dan itu mungkin bukan yang Anda inginkan. Saya tahu dengan mvn Anda mendapatkan pengaturan memori yang berbeda untuk mengkompilasi vs lari dan Anda mungkin mendapatkan itu juga.


2
2017-12-06 00:28