some thoughts on ClassValue

Peter Levart peter.levart at gmail.com
Fri Apr 26 05:44:54 PDT 2013


On 04/26/2013 09:59 AM, Jochen Theodorou wrote:
> Hi all,
>
> basically ClassValue is there so that my runtime/framework or whatever
> can store information and bind it to a class. The information is then
> available as long as the class exists. In Groovy3 I am going to use this
> for meta classes.
>
> Some time ago a user came up with a special need, he wanted to be able
> to replace the groovy runtime at runtime but could not do so because of
> classes being referenced that keep classloaders alive, which then lock
> the jar on the file system on windows.
>
> This did let me to the thought, that as soon as I start storing meta
> classes using ClassValue, my Groovy runtime will never unload again as
> soon as I store for the example a meta class on ArrayList (which is
> likely to happen) or Object, or any other java core class for that
> matter. This makes me think that I should not directly use ClassValue to
> enable unloading... but I also do not want unloading to happen when I
> still need the value.
>
> Does anyone have any idea on now to solve this problem?
>
> bye blackdrag
>

Hi Jochen,

It seems you have similar issues that for example j.l.r.Proxy has. It 
spins a class implementing given interfaces, defines it with a given 
ClassLoader and then caches it for future-use. The situation with 
j.l.r.Proxy is simpler than your's, I assume. Could you describe in some 
more detail, what are "meta classes" in groovy runtime in terms of how 
they are generated (lazily at runtime or ahead of runtime?), what 
dependencies they can have and who is dependent on them. I assume they 
are generated at runtime, since if they were accessible as class files 
on the classpath of some loader, you would not have to design your own 
caching/loading/defining layer (Class.forName() would do). That's still 
an option if you create your own ClassLoader subclass that would use a 
naming convention (say groovymeta.some.pkg.ClassName would be the name 
of meta class "belonging" to some.pkg.ClassName main class) and use that 
ClassLoader as the class loader for groovy apps. But that's hard to 
enforce in various environments... So dynamic generation then.

You typically would want to define a class with the ClassLoader that 
also "sees" all the dependencies of the class. But there could be 
several ClassLoaders in a runtime that are suitable in a given 
situation. You would choose the right one depending on the lifetime of 
the generated class and the possible users of that class. And you would 
want the Class object of the "meta class" to be cached via a 
WeakReference<Class>, so that when all the users of the class are gone 
the class itself becomes one step to eligible to GC. It will not be 
GC-ed until the ClassLoader that defined it becomes eligible to GC 
(since the ClassLoader maintains explicit hard-references to all the 
Class objects for classes that it has defined). And each class maintains 
an implicit reference to the ClassLoader that defined it. So when all 
the users of all classes defined by a single ClassLoader are gone and 
the ClassLoader is not reachable any more, the whole graph of 
ClassLoader with all it's Class objects is GC-ed. It's that simple.

The question is how to most effectively design the structure so that you 
can quickly obtain the cached Class object and use the class represented 
by it. One part of the lookup "key" seems to be the "main class" that 
the "meta class" belongs to. So ClassValue is one option. But I can 
imagine you would want to support groovy runtime in environments such as 
app servers where the groovy runtime is deployed at the system level and 
the contents of a metaclass belonging to some system class (say 
ArrayList) is supplied by the deployed application and there could be 
several deployed applications, each contributing it's own different 
"meta class" for ArrayList. So the main class is not the only "key" for 
lookup. I would imagine the ClassLoader of the deployed application is 
the other part of the "key" and you would want to define a separate meta 
class with each application ClassLoader for the same main class. So the 
most general approach would be the structure similar to the following:


Map<WeakReference<ClassLoader>, ClassValue<WeakReference<Class>>>
                   ^                                      ^
                   |                                      meta class
                   the defining class loader of the meta class

which is equivalent to:

Map<WeakReference<ClassLoader>, Map<WeakReference<Class>, 
WeakReference<Class>>>
                   ^ ^                     ^
                   | |                     meta class
                   |                               main class
                   the defining class loader of the meta class


  ... with the hashCode/equals of the WeakReferences suitably overriden 
of course.


Regards, Peter



More information about the mlvm-dev mailing list