The version with a WeakHashMap and first getting ClassInfo without
synchronization (which would could not be used in the end anyway)
appeared in some quick (probably not representative) tests with
concurrent access to be about 10-20% slower than the current
implementation. Similar result also when I split up into 4096
WeakHashMap instances in an array of clazz.hashCode()%4096 and always
synchronizing on get().
I looked into the source of ClassValue. I had naively expected it to
contain some native code or otherwise interact more directly with the
VM, but there is only a new field in the Class class that it uses. So
there is a hard link from the class via that field to ClassInfo in the
case of Groovy, which I guess prevents "on-the-fly" garbage collection
because ClassInfo contains lots of stuff with hard references to the
class. And with the pre Java 7 implementation I presume the situation is
similar. (With a WeakHashMap that is different because the value does
not count, the entry can be collected independently of the value and it
could be argued that ClassValue should have been implemented in a way
that would have had the same behavior, if I my reasoning is correct.)
So maybe refactoring to always using WeakReference<Class> in all objects
stored in ClassInfo (meta classes, caches, ...) would be sufficient to
get "on-the-fly" garbage collection (i.e. before the maximum on
Metaspace or Heap is reached)? And would the additional weakRef.get()
calls maybe have again a noticeable effect on performance? I won't try
this refactoring myself, but if someone else wants to try this?
Well, at least I think I might start to understand the problem... ;)
Alain