AnonymousClassLoader in JRuby

Charles Oliver Nutter charles.nutter at sun.com
Sat Apr 26 14:38:53 PDT 2008


Another thought occurs about how/where this would be useful. Consider it 
a "duh" moment for me, given that much of this work is being driven by 
JSR292...

ACL will be incredibly useful for generating inexpensive method handles. 
Duh.

So you have a template that represents the general way in which you want 
the handle to be structured. All that actually changes then in the many 
handles you load is that the constant pool has been patched for the 
appropriate target class and method. So where in JRuby we have to 
generate a fresh new class every time (some sharing would be possible, 
but it's cumbersome), with ACL we'd essentially just be generating 
constant-pool-patched versions of the same class. They'd look and smell 
the same at the bytecode level, but because of altered constant pool 
changes they'd actually invoke different code and follow different paths.

I think I'm getting it now. Outside the utility of having no parent 
classloader to hold a hard reference to a class, ACL doesn't do a lot 
more for us than OneShotClassLoader. But for method handles, I see the 
truth of it.

John Rose: We need to talk about the plans for a backported library to 
support this scenario. It's exactly the sort of thing I've wanted to 
morph JRuby's InvocationMethodFactory into, and it would help so many 
languages that want to be able to avoid reflection overhead for method 
invokers while simultaneously being able to juggle method handles in 
arbitrary data structures.

Charles Oliver Nutter wrote:
> Ok, reading back over some notes and anonk.txt I think I understand a 
> bit better. Tell me if I'm understanding things right.
> 
> java.dyn.AnonymousClassLoader is not a java.lang.ClassLoader itself. It 
> bypasses the normal classloading chain by calling the new Unsafe method 
> that allocates and loads a class directly. Given a byte[] and a host 
> class, you can use AnonymousClassLoader to simply load a class; you can 
> also use it to produce patched versions of a class, reducing the 
> metadata necessary for each new class loaded by only altering the 
> constant pool.
> 
> The classes are not associated with a classloader, and so the normal 
> overhead we face of having a classloader-per-class (aggravated by a 
> class-per-method in JRuby) is reduced.
> 
>  From an API perspective, we've largely achieved the "GCable class 
> loading" concept in JRuby out of necessity. But on JDK6 and lower we pay 
> the cost of having all those classes holding on to a clasloader in memory.
> 
> I have been unable to see an improved memory cost, but it's possible the 
> actual cost of those classloaders in this test is outweighed by other 
> JRuby runtime metadata associated with a given JITed method. Perhaps a 
> simple Java test that loads 10_000 really simple classes via a 
> OneShotClassLoader and via AnonymousClassLoader would be a better way to 
> measure this?
> 
> It's also possible that the ClassCache concept would be useful/important 
> to include or publish along with AnonymousClassLoader, since I would 
> expect that most people loading classes anonymously will want a way to 
> cache and retrieve already-loaded versions of code they're trying to 
> load. This also sees like it might be necessary since anonymous classes 
> will be otherwise impossible to look up, forcing even the same code in 
> different places to instantiate a new class. Any thoughts on this? 
> ClassCache (unpatched) in its entirety is here:
> 
> http://svn.codehaus.org/jruby/trunk/jruby/src/org/jruby/util/ClassCache.java
> 
> FYI, in JRuby, the key we use is generated by rendering the Ruby AST 
> into a string containing a sexp representation of the code. This allows 
> multiple instances of JRuby using the same class cache to share each 
> others anonymously-loaded method bodies.
> 
> - Charlie
> 
> Charles Oliver Nutter wrote:
>> I've managed to wire the AnonymousClassLoader into JRuby. A patch is 
>> attached, that will probably be rather confusing to anyone unfamiliar 
>> with JRuby.
>>
>> ClassCache is basically a smart class-loading utility that can be used 
>> to share loaded classes across JRuby instances without keeping hard 
>> references to them and preventing them from unloading.
>>
>> AnonymousClassLoader is an all-static utility class that wraps the logic 
>> of instantiating "one-shot" classloaders for loading bodies of code. In 
>> this case, it either uses java.dyn.AnonymousClassLoader or our own 
>> "OneShotClassLoader" which is not anonymous but which is used for only a 
>> single class.
>>
>> The code generally appears to work about the same with 
>> java.dyn.AnonymousClassLoader available, which is good. But I'm having 
>> trouble quantifying the benefit to JRuby. I'd like to be able to show 
>> how it helps, but memory profiles look practically the same between the 
>> version using an OneShotClassLoader per method body and the version 
>> using AnonymousClassLoader per method body. I have not done a lot of 
>> work to isolate the cost of loading, but it seems to be unnoticeable in 
>> my simple benchmark which defines 100_000 Ruby methods and forces them 
>> to JIT.
>>
>> So the runtime benefits may not be so great. The practical benefits, 
>> such as being able to chuck byte[] into AnonymousClassLoader without 
>> decorating class names and ensuring uniqueness, I have not yet utilized 
>> in this code. Those benefits may show how writing class caches like the 
>> one in JRuby are made a lot easier. For the moment, in order to allow 
>> JRuby to support both MLVM work and pre-JDK7 JVMs, this patch still does 
>> name-mangling to ensure methods are unique.
>>
>> I think part of my confusion is that originally I desired a class loader 
>> for which I could have a single instance I would throw *many* byte[] at, 
>> and they'd all be loaded using that classloader but without hard 
>> references and without the overhead of a classloader-per-method. But the 
>> AnonymousClassLoader interface appears to one exactly one byte[] per 
>> instance, though it does have considerably reduced in-memory cost per 
>> AnonymousClassLoader instance.
>>
>> Basically, what I've been looking for to make my life easier and memory 
>> costs lower is:
>>
>> ClassLoader cl = someClassLoader....;
>> Class first = cl.defineClass(firstClass);
>> Class second = cl.defineClass(secondClass);
>> first = null; // and at some point I would expect the class to GC
>>
>> Is this the purpose of AnonymousClassLoader? Am I doing it wrong? I'll 
>> be poking around for example code now.
>>
>> - Charlie
>>
>>
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> mlvm-dev mailing list
>> mlvm-dev at openjdk.java.net
>> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
> 
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev




More information about the mlvm-dev mailing list