I'm reading Clojure Programming book by O'Reilly..
I came over an example of head retention.
First example retains reference to d
(I presume), so it doesnt get garbage collected:
(let [[t d] (split-with #(< % 12) (range 1e8))]
[(count d) (count t)])
;= #<OutOfMemoryError java.lang.OutOfMemoryError: Java heap space>
While second example doesnt retain it, so it goes with no problem:
(let [[t d] (split-with #(< % 12) (range 1e8))]
[(count t) (count d)])
;= [12 99999988]
What I don't get here is what exactly is retained in which case and why.
If I try to return just [(count d)]
, like this:
(let [[t d] (split-with #(< % 12) (range 1e8))]
[(count d)])
- it seems to create same memory problem. Why is that?
Further, I recall reading that count
in every case realizes/evaluates a sequence.
So, i need that clarified.
If I try to return (count t)
first, how is that faster/more memory efficient then if I dont return it at all?
And what & why gets retained in which case?
I'm reading Clojure Programming book by O'Reilly..
I came over an example of head retention. First example retains reference to
d
(I presume), so it doesnt get garbage collected:(let [[t d] (split-with #(< % 12) (range 1e8))] [(count d) (count t)]) ;= #<OutOfMemoryError java.lang.OutOfMemoryError: Java heap space>
While second example doesnt retain it, so it goes with no problem:(let [[t d] (split-with #(< % 12) (range 1e8))] [(count t) (count d)]) ;= [12 99999988]
If I try to return just[(count d)]
, like this:(let [[t d] (split-with #(< % 12) (range 1e8))] [(count d)])
- it seems to create same memory problem. Why is that?
Further, I recall reading that
count
in every case realizes/evaluates a sequence. So, i need that clarified.
(let [[t d] (split-with #(< % 12) (range 1e8))]
[(count d) (count t)])
Thank you for your response, Marko.
I want to clarify one more thing:(let [[t d] (split-with #(< % 12) (range 1e8))] [(count d) (count t)])
does this mean that while (count d) is realizing (range 1e8) seq, it becomes (also) realized within t, therefore
it doubles (range 1e8) in memory causing OOME while (count d) is still not finished?
Also, you say "As count realizes one element after another, it doesn't on its own retain a reference to the past elements."
Does this mean that, eg. in repl, when I do some (count xyz) and it realizes xyz, It will later need to be reevaluated (realized again) if I require xyz within repl (I presume that if I require xyz later within file, it wont be GC due to it and clojure will know it shouldnt be GC)