I started getting StackOverflow exceptions today around
clojure.lang.Keyword (I'm running clojure 1.2.0, but the code doesn't
seem to be different in github master).
It looks like intern is keeping a ConcurrentHashMap of SoftReference
objects.  The problem is that when the SoftReference exists, but the
payload of the SoftReference (the thing you get from .get()) is null,
it tries to call intern again:

public static Keyword intern(Symbol sym){
        Util.clearCache(rq, table);
        Keyword k = new Keyword(sym);
        SoftReference<Keyword> existingRef = table.putIfAbsent(sym, new
SoftReference<Keyword>(k,rq));
        if(existingRef == null)
                return k;
        Keyword existingk = existingRef.get();
        if(existingk != null)
                return existingk;
        //entry died in the interim, do over
        return intern(sym);
}

It's counting on Util.clearCache and a ReferenceQueue at rq to clear
out objects that have been GC'd, but the documentation for
SoftReferences says:

"Suppose that the garbage collector determines at a certain point in
time that an object is softly reachable. At that time it may choose to
clear atomically all soft references to that object and all soft
references to any other softly-reachable objects from which that
object is reachable through a chain of strong references. At the same
time or at some later time it will enqueue those newly-cleared soft
references that are registered with reference queues."

This means to me that it is non-deterministic when the VM will enqueue
the reference into the ReferenceQueue, you just know that it will
happen at some point in time.  I'm assuming that my code was in a
state where the Keyword got GC'd, but that hadn't been enqueued in the
ReferenceQueue yet and thus the SoftReference wasn't cleared out of
the Map and it recursed until it got a StackOverflow.

I think a simple fix for this could be to do a "table.remove(sym,
existingRef)" right before the "return intern(sym);".  This would
ensure that the recursive call will succeed and since Util.clearCache
is doing the same call, shouldn't have any adverse side-effects.

--Eric

-- 
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
Note that posts from new members are moderated - please be patient with your 
first post.
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