I'm trying to implement round-tripping from LinkedHashMaps to Clojure collections. The implementation below works for smaller collections, but larger collections raise OutOfMemoryError: GC overhead limit exceeded
. Below is a generative test that passes, when the number of tests is small (~10), but exhausts memory for larger numbers of tests (~100).
I would appreciate any tips how to reduce the memory requirements of the implementation as well as general tips on how to improve the code's quality.
(import '[clojure.lang IPersistentMap IPersistentVector]
'[java.util ArrayList LinkedHashMap])
(defprotocol LinkedHashMappable
"Convert Clojure data structure to LinkedHashMap."
(->linked-hash-map [data]))
(extend-protocol LinkedHashMappable
IPersistentMap
(->linked-hash-map [m]
(let [lhm (LinkedHashMap.)]
(doseq [[k v] m]
(.put lhm
(if (keyword? k) (name k) k)
(->linked-hash-map v)))
lhm))
IPersistentVector
(->linked-hash-map [v]
(let [alist (ArrayList.)]
(doseq [i v] (.add alist (->linked-hash-map i)))
alist))
Object
(->linked-hash-map [o] o))
(defprotocol Clojurizable
"Convert LinkedHashMap to Clojure data structure."
(->clj [lhm]))
(extend-protocol Clojurizable
LinkedHashMap
(->clj [lhm]
(reduce (fn [m [k v]]
(assoc m (keyword k) (->clj v)))
{}
(iterator-seq (.. lhm entrySet iterator))))
ArrayList
(->clj [alist]
(mapv ->clj alist))
Object
(->clj [o] o))
; ----- Test -----
(require '[clojure.test.check :as tc]
'[clojure.test.check.generators :as gen]
'[clojure.test.check.properties :as prop])
(def map-generator
(gen/recursive-gen (fn [inner]
(gen/map gen/keyword (gen/one-of [(gen/map gen/keyword inner)
(gen/vector inner)])))
gen/string))
(def linked-hash-map-round-tripping
(prop/for-all [m map-generator]
(= (->clj (->linked-hash-map m)) m)))
; The test passes for smaller numbers of tests (~10), but exhausts memory for larger numbers (~100).
#_(tc/quick-check 100 linked-hash-map-round-tripping)