this allows keywords to be garbage collected. the weakhashmap does
require locking. the reason for both the weakhashmap and the
weakreference is that keywords store a ref to the corresponding symbol
(which is used for equality). if there is no reference to the symbol
(which cannot happen if the corresponding keyword exists) the whole
mapentry can be gc'ed. if there is no reference to the keyword, the
keyword can be gc'ed, in which case it no longer refs the symbol, and
if that was the last reference to the symbol, the weakhashmap can drop
the entry.
the current patch also unfortunately includes a lot of whitespace
changes, which may or may not be acceptable.
https://gist.github.com/4c9fce8ea6f611589ea3
--
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?
It's really painful to give up the Concurrent part of the CHM for this - this introduces a JVM-wide global lock in Keyword which is hit on every write AND read and that critical section is a lot wider. You're unlikely to see any difference with a small number of threads, but for certain multi-threaded programs, I can imagine this would be tragically bad. It strikes me that indeed the very programs that are most likely to suffer heap pollution issues are also most likely to need the concurrency here.
[The Map implementations in the JDK are actually my canonical example of why inheritance sucks and composition rules. No way to mix/match Concurrent, Identity, Weak key behavior. Google Collections did a far better job with MapMaker.]
Presuming Clojure doesn't want a dependency on google collections, it is possible to basically start from the public domain version of CHM and modify it to add the Weak key behavior to get a WeakConcurrentHashMap. That has the downside of introducing nasty mostly-copied collection code into clojure of course.
Alex
> href="https://gist.github.com/4c9fce8ea6f611589ea3" target=_blank
> >https://gist.github.com/4c9fce8ea6f611589ea3
--
And what is
> good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these
> things?
--
You received this message because you are subscribed to
> the Google Groups "Clojure Dev" group.
To post to this group, send email to
>
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com.
To
> unsubscribe from this group, send email to clojure-dev+
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com.
For
> more options, visit this group at
> http://groups.google.com/group/clojure-dev?hl=en.
user=> (dotimes [_ 1e9] (keyword (name (gensym))))
has been running for almost 10 hours now, so I think keywords are getting gc'ed
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
>
>
--
Seems like we can take as requirements:
1) keywords must be interned (identity semantics, not just equality)
2) keywords are dynamic and may be introduced over the life of a running process
3) unreferenced keywords could be reclaimed without affecting programs
4) creating keyword instances should be fast and highly concurrent
We're trying to address #3 but the proposed solution steps backwards on #4 (by inspection at least).
I think one improvement would be to do a (safe) double-check (my apologies if I typo as I didn't try this in an IDE):
private static Map<Symbol, WeakReference<Keyword>> table = new WeakHashMap();
private static ReadWriteLock lock = new ReentrantReadWriteLock();
public static Keyword intern(Symbol sym) {
WeakReference<Keyword> existingKey = null;
try {
// do checks under the READ lock (allowing concurrent checks)
lock.readLock().lock();
existingKey = table.get(sym);
if(existingKey != null) {
Keyword k = existingKey.get();
if(k != null) {
return k; // common case of returning an existing keyword
}
} finally {
// you cannot upgrade a RRWL from read to write, must relinquish read
lock.readLock().unlock();
}
// create this outside the critical section
newKey = new WeakReference(new Keyword(sym));
// acquire WRITE lock and RE-check if some other thread beat us in the gap
lock.writeLock().lock();
try {
checkKey = table.get(sym);
if(checkKey != null) {
Keyword k = checkKey.get();
if(k != null) {
// another thread beat us, so use his keyword
return k;
}
}
// otherwise, we won and created the new key
table.put(sym,newKey);
return newKey;
} finally {
lock.writeLock().unlock();
}
}
This implementation at least gives you read concurrency on the checks and moves a bit more code outside the critical section. Writes on new keywords will still collide.
I think the ideal solution would be to create a ConcurrentWeakHashMap and use putIfAbsent though.
Alex
----- Original Message ----
> From: Kevin Downey <red...@gmail.com>
> To: cloju...@googlegroups.com
> Sent: Fri, June 18, 2010 11:57:17 AM
> Subject: Re: weakref keywords RFC
>
> without the patch it fails in a few minutes
On Fri, Jun 18, 2010 at 9:55
> AM, Kevin Downey <
> href="mailto:red...@gmail.com">red...@gmail.com> wrote:
>
> well
>
> user=> (dotimes [_ 1e9] (keyword (name
> (gensym))))
>
> has been running for almost 10 hours now, so I think
> keywords are getting gc'ed
>
> On Thu, Jun 17, 2010 at 10:29 PM,
> Alex Miller <
> href="mailto:alexd...@yahoo.com">alexd...@yahoo.com>
> ymailto="mailto:red...@gmail.com"
> href="mailto:red...@gmail.com">red...@gmail.com>
>>> To:
> Clojure Dev <
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com>
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com">
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com.
>>
> To
>>> unsubscribe from this group, send email to
> clojure-dev+
>>> ymailto="mailto:
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com"
>>>
> href="mailto:
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com">
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com.
>>
> For
>>> more options, visit this group at
>>>
> http://groups.google.com/group/clojure-dev?hl=en.
>>
>>
> --
>> You received this message because you are subscribed to the
> Google Groups "Clojure Dev" group.
>> To post to this group, send email
> to
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com.
>>
> To unsubscribe from this group, send email to clojure-dev+
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com.
>>
> For more options, visit this group at
> href="http://groups.google.com/group/clojure-dev?hl=en" target=_blank
> >http://groups.google.com/group/clojure-dev?hl=en.
>>
>>
>
>
>
>
> --
> And what is good, Phaedrus,
> And what is not good—
>
> Need we ask anyone to tell us these things?
>
--
And
> what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell
> us these things?
--
You received this message because you are
> subscribed to the Google Groups "Clojure Dev" group.
To post to this group,
> send email to
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com.
To
> unsubscribe from this group, send email to clojure-dev+
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com.
For
> more options, visit this group at
> href="http://groups.google.com/group/clojure-dev?hl=en" target=_blank
> >http://groups.google.com/group/clojure-dev?hl=en.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
>
>
--
I have not written any tests, I'm just going by the reasoning that a single global lock on both reads and writes will be an issue. I started working on a multi-threaded test for you but I don't know when I'll have time to complete it.
Alex
----- Original Message ----
> From: Kevin Downey <red...@gmail.com>
> To: cloju...@googlegroups.com
> Sent: Fri, June 18, 2010 2:56:14 PM
> Subject: Re: weakref keywords RFC
>
> I think adding an extra lock introduces more complexity. do you
> have
benchmarks where it makes a difference?
On Fri, Jun 18, 2010 at
> 11:38 AM, Alex Miller <
> Sent: Fri, June 18, 2010 11:57:17 AM
>> Subject: Re: weakref keywords
> RFC
>>
>> without the patch it fails in a few
> minutes
>
> On Fri, Jun 18, 2010 at 9:55
>> AM, Kevin
> Downey <
>> href="mailto:
> href="mailto:red...@gmail.com">red...@gmail.com">
> ymailto="mailto:red...@gmail.com"
> href="mailto:red...@gmail.com">red...@gmail.com>
> wrote:
>>
>> well
>>
>> user=> (dotimes
> [_ 1e9] (keyword (name
>> (gensym))))
>>
>> has been
> running for almost 10 hours now, so I think
>> keywords are getting
> gc'ed
>>
>> On Thu, Jun 17, 2010 at 10:29 PM,
>> Alex
> Miller <
>> href="mailto:
> href="mailto:alexd...@yahoo.com">alexd...@yahoo.com">
> ymailto="mailto:alexd...@yahoo.com"
> href="mailto:red...@gmail.com">red...@gmail.com"
>>
> href="mailto:
> href="mailto:red...@gmail.com">red...@gmail.com">
> ymailto="mailto:red...@gmail.com"
> href="mailto:red...@gmail.com">red...@gmail.com>
>>>>
> To:
>> Clojure Dev <
>> href="mailto:
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com">
> ymailto="mailto:cloju...@googlegroups.com"
> target=_blank >https://gist.github.com/4c9fce8ea6f611589ea3"
> target=_blank
>> >
> href="https://gist.github.com/4c9fce8ea6f611589ea3" target=_blank
> >https://gist.github.com/4c9fce8ea6f611589ea3"
> target=_blank
>>>>
>> >
>> >
> href="https://gist.github.com/4c9fce8ea6f611589ea3" target=_blank
> >https://gist.github.com/4c9fce8ea6f611589ea3
>>>
>>>
>>
> --
>>> And what is
>>>> good,
> Phaedrus,
>>> And what
>> is not good—
>>> Need
> we ask anyone to tell us these
>>>>
>>
> things?
>>>
>>> --
>>> You received this
> message because
>> you are subscribed to
>>>> the Google
> Groups "Clojure Dev"
>> group.
>>> To post to this group,
> send email
>> to
>>>>
>>>>
> href="mailto:
>> ymailto="mailto:
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com"
>>
> href="mailto:
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com">
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com">
>>
> ymailto="mailto:
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com"
>>
> href="mailto:
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com">
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com.
>>>
>>
> To
>>>> unsubscribe from this group, send email to
>>
> clojure-dev+
>>>> ymailto="mailto:
>> ymailto="mailto:
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com"
>>
> href="mailto:
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com">
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com"
>>>>
>>
> href="mailto:
>> href="mailto:
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com">
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com">
>>
> ymailto="mailto:
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com"
>>
> href="mailto:
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com">
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com.
>>>
>>
> For
>>>> more options, visit this group
> at
>>>>
>>
> http://groups.google.com/group/clojure-dev?hl=en.
>>>
>>>
>>
> --
>>> You received this message because you are subscribed to
> the
>> Google Groups "Clojure Dev" group.
>>> To post to
> this group, send email
>> to
>> href="mailto:
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com">
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com.
>>>
>>
> To unsubscribe from this group, send email to clojure-dev+
>>
> ymailto="mailto:
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com"
>>
> href="mailto:
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com">
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com.
>>>
>>
> For more options, visit this group at
>> href="
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com">
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com.
>
> To
>> unsubscribe from this group, send email to
> clojure-dev+
>> ymailto="mailto:
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com"
>>
> href="mailto:
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com">
> ymailto="mailto:unsub...@googlegroups.com"
> href="mailto:unsub...@googlegroups.com">unsub...@googlegroups.com.
>
> For
>> more options, visit this group at
>> href="
> href="http://groups.google.com/group/clojure-dev?hl=en" target=_blank
> >http://groups.google.com/group/clojure-dev?hl=en" target=_blank
>>
> >
> >http://groups.google.com/group/clojure-dev?hl=en.
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure Dev" group.
> To post to this group, send email to
> ymailto="mailto:cloju...@googlegroups.com"
> href="mailto:cloju...@googlegroups.com">cloju...@googlegroups.com.
>
> To unsubscribe from this group, send email to clojure-dev+
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
>
>
--
here is the patch without all the whitespace munging