Skip to content

Instantly share code, notes, and snippets.

@sjl
Created August 16, 2011 18:28
Show Gist options
  • Save sjl/1149787 to your computer and use it in GitHub Desktop.
Save sjl/1149787 to your computer and use it in GitHub Desktop.
Clojure Delay + GC Question
(defn random-byte-array
"Return a large byte-array of random bytes."
[]
(byte-array (map byte
(take (* 1024 100)
(cycle [(rand-int 100) (rand-int 100) (rand-int 100)])))))
(defn dtest [arr]
(delay (alength arr)))
(def testlens (doall (map dtest (repeatedly 5 random-byte-array))))
; We now have a non-lazy sequence of 5 delay elements, each of which should be
; referencing a big byte array.
;
; [ (delay ...), (delay ...), ... ]
; | |
; v v
; [bytes...] [bytes...]
; Force all the delays.
(dorun (map force testlens))
; Ideally the elements in the testlens map would no longer reference the byte arrays,
; so they could be gabage collected.
;
; [ (delay ...), (delay ...), ... ]
; | |
; v v
; cached result cached result
;
; [bytes...] [bytes...] <---- Ready for GC
(System/gc)
(println
; Each time through this loop we'll build a vector of 5 delays pointing to big
; arrays, and force them.
;
; If the arrays aren't referenced after the force we should be fine, because the
; system can GC the old byte-arrays when it needs space for new ones.
;
; If they ARE still referenced we'll keep consuming memory until we're done with
; the entire loop (and run out using the default heap size).
(loop [n 1000
lensets []]
(if (= n 0)
lensets
(let [delayed-len-list (doall (map dtest
(repeatedly 5 random-byte-array)))]
(println n)
(recur (dec n)
(conj lensets (doall (map force delayed-len-list))))))))
; When I ran this I didn't run out of memory, so it seems delays remove the
; references to their args once they cache the value.
;
; Looking at https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Delay.java#L30-37
; seems to confirm this theory.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment