Possible class loader related optimization

Adrian Tarau adrian.tarau at gmail.com
Fri Jul 20 12:39:58 PDT 2012


I Eric,

Create your own ObjectInputStream and resolve classes as you to match 
your needs. If your class loader hierarchy is fixed you can even throw 
in some caching. Bellow you can find an implementation which gives me 
huge improvements over deserialization.

Thanks,
Adrian Tarau.

private static ThreadLocal<Map<String, Class<?>>> CLASS_CACHE = new 
ThreadLocal<Map<String, Class<?>>>() {
         @Override
         protected Map<String, Class<?>> initialValue() {
             return new HashMap<String, Class<?>>();
         }
     };

     public static class MyObjectInputStream extends ObjectInputStream {

         private ClassLoader classLoader;

         {
             classLoader = getClass().getClassLoader();
         }

         MyObjectInputStream(java.io.InputStream in) throws IOException {
             super(in);
         }

         @Override
         protected Class<?> resolveClass(ObjectStreamClass desc) throws 
IOException, ClassNotFoundException {
             try {
                 return doResolveClass(desc);
             } catch (Exception e) {
                 CLASS_CACHE.get().clear();
             }
             return doResolveClass(desc);
         }

         private Class<?> doResolveClass(ObjectStreamClass desc) throws 
IOException, ClassNotFoundException {
             Map<String, Class<?>> cache = CLASS_CACHE.get();
             Class<?> clazz = cache.get(desc.getName());
             if (clazz != null) {
                 return clazz;
             }
             try {
                 clazz = classLoader.loadClass(desc.getName());
                 cache.put(desc.getName(), clazz);
             } catch (ClassNotFoundException e) {
                 // try something else
             }
             if (clazz != null) {
                 return clazz;
             }
             ClassLoader contextClassLoader = 
Thread.currentThread().getContextClassLoader();
             if (contextClassLoader != null) {
                 try {
                     clazz = contextClassLoader.loadClass(desc.getName());
                     cache.put(desc.getName(), clazz);
                 } catch (ClassNotFoundException e) {
                     // try something else
                 }
             }
             if (clazz == null) {
                 clazz = super.resolveClass(desc);
                 cache.put(desc.getName(), clazz);
             }
             return clazz;
         }
     }

On 07/20/2012 03:32 PM, Eric Caspole wrote:
> Hello JVM team,
>
> While running a customer app that frequently uses ObjectInputStream, 
> we noticed a lot of time spent in JVM_LatestUserDefinedLoader and some 
> related methods like 
> vframeStreamCommon::skip_reflection_related_frames. When doing 
> ObjectInputStream.read(), it needs to find the class loader that goes 
> with the user application call site to get the class of the freshly 
> read object. This operation walks down the stack on the thread looking 
> at the nmethod's classes to find the owner class's loader.
>
> But it appears this application, like probably a great many real world 
> applications out there, uses only one class loader, the primordial 
> sun.misc.Launcher$AppClassLoader.
>
> I think if there is only one user class loader in play, we should be 
> able to cache it and avoid the stack walk. More complicated cases like 
> web app servers, where often each web app is run in its own loader, 
> might still require the stack walk lookup.
>
> I have made a webrev where I cache a ref to the primordial 
> sun.misc.Launcher$AppClassLoader and use the cached value for these 
> JVM_LatestUserDefinedLoader lookups, and flush the cache and force a 
> normal stack walk lookup if a new user class loader comes into play.
> Since our application only uses the primordial loader, this 
> optimization was effective and sped it up a few percent.
>
> My webrev is at: 
> http://cr.openjdk.java.net/~ecaspole/latestloader/webrev/
>
> I attached here a small test case using ObjectInputStream that shows 
> this use case.
>
> Please let me know your comments. I know there are a lot of special 
> purpose class loaders used internally in the JDK but I think most of 
> them never run code that will arrive at ObjectInputStream.read().
>
> Regards,
> Eric

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/attachments/20120720/a63396bc/attachment.html 


More information about the hotspot-runtime-dev mailing list