On Feb 2, 10:06 am, Keith Bennett <keithrbenn...@gmail.com> wrote:
> I'm curious to know how to minimize memory consumption in Clojure for
> large lists.  I did the following test in repl:
>
> (def d ())
> (dotimes [_ 100000] (def d (cons "x" d)))

Let me translate this into pseudocode for you:

Make d into a global reference wrapped with a mutex
Set d to point to an empty list
for i = 1 to 100000:
    If the symbol d has not yet been defined previously:
        Create it
    Within a critical section protecting d:
        Replace the value of d with (cons "x" d)

Note in particular that

1. You're probably doing it wrong if you call "def" more than twice
for the same symbol.  "def" is NOT a replacement for SETF (in Common
Lisp) or "set!" (in Scheme).  The point of Clojure is not to use
destructive updates whenever possible.
2. If you keep the head of a sequence, as in "(def a (map ...))", you
have to store all elements of the sequence in memory.

> Are there alternate strategies for building a large sequence that
> would consume less memory per element?

If you _build_ the sequence, you'll have to store the whole sequence.
If you construct the sequence lazily, only use one element of it at a
time, and don't keep that element anywhere, then you'll never need to
store the whole sequence.  But if you store the head of the sequence
(e.g., with a def), then you'll have to store all elements of the
sequence that you visit.  If you print the whole sequence (as you
would at the REPL), then you visit all the elements of the sequence.
Therefore, in keeping the head of the sequence and printing it, you're
storing the whole sequence in memory.  That's where all the list
objects (a.k.a. conses) come from.  The GC doesn't clean them up
because you still have references to all of them; they are still
reachable.  You could do GC a million times and they would all stay.

That's how lazy seqs work.  It has nothing to do with Clojure and
everything to do with the language construct.  If you don't like it,
then check out "streams," which Rich is currently building.  Streams
are ephemeral as long as you don't put their elements into a seq.  Of
course that means you can only iterate over a stream once.  Again,
that has nothing to do with Clojure and everything to do with the
language construct.

mfh

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to