[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-2990) Bad usage of ClassLoader.loadClass() for Java6 in SerializationHelper$CustomObjectInputStream - deserialization bottleneck for arrays

Steve Ebersole (JIRA) noreply at atlassian.com
Tue Nov 17 12:41:08 EST 2009


    [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-2990?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=34645#action_34645 ] 

Steve Ebersole commented on HHH-2990:
-------------------------------------

The end result of this was actually 2fold:
1) Change SerializationHelper$CustomObjectInputStream to use the Class.forName(String,boolean,ClassLoader) form
2) alter the way deserialization occrs to pass in the (best effort) classloader to use whenever possible, specifically the classloader of the returnedClass for various org.hibernate.type.Type impls which would be the classloader of the user classes

> Bad usage of ClassLoader.loadClass() for Java6 in SerializationHelper$CustomObjectInputStream - deserialization bottleneck for arrays
> -------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HHH-2990
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2990
>             Project: Hibernate Core
>          Issue Type: Bug
>    Affects Versions: 3.2.5
>         Environment: Hibernate 3.2.5, Java 6 Sun (any), any platform (tested Linux x64, Mac x64 (J6dp1))
>            Reporter: Tom Eicher
>            Assignee: Steve Ebersole
>             Fix For: 3.5
>
>
> Sun has "clarified" (others say modified) the API of "ClassLoader.loadClass()" and no longer allows this to be called for arrays, e.g. String[].
> ( see: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6500212 and duplicates )
> and states that this has always been very unstable to use/do in the first place.
> So trying to load an array of something using this method results in ClassNotFoundException.
> The correct thing to do is call Class.forName(className,false,myClassLoader); instead of myClassLoader.loadClass(className);
> In SerializationHelper$CustomObjectInputStream.resolveClass() we do
> 			ClassLoader loader = Thread.currentThread().getContextClassLoader();
> 			try {
> 				resolvedClass = loader.loadClass(className);
> 				log.trace("Class resolved through context class loader");
> 			}
> 			catch(ClassNotFoundException e) {
> 				log.trace("Asking super to resolve");
> 				resolvedClass = super.resolveClass(v);
> 			}
> which results in the deserialization process for a String[] always searching String[] in all the application's jars/wars/etc before really loading it.
> The bad thing is, loadClass() is synchronized.
> In our case, we have multiple threads loading database rows containing String[]s, which results in one Thread doing
> INFO   | jvm 1    | 2007/11/30 16:56:44 |    java.lang.Thread.State: RUNNABLE
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.util.zip.ZipFile.getEntry(Native Method)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.util.zip.ZipFile.getEntry(ZipFile.java:149)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       - locked <0x00002aaab4047c20> (a java.util.jar.JarFile)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.util.jar.JarFile.getEntry(JarFile.java:206)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.util.jar.JarFile.getJarEntry(JarFile.java:189)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at sun.misc.URLClassPath$JarLoader.getResource(URLClassPath.java:754)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at sun.misc.URLClassPath.getResource(URLClassPath.java:168)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.net.URLClassLoader$1.run(URLClassLoader.java:192)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.security.AccessController.doPrivileged(Native Method)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       - locked <0x00002aaab4025998> (a org.apache.catalina.loader.StandardClassLoader)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       - locked <0x00002aaab4095a68> (a org.apache.catalina.loader.StandardClassLoader)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1346)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1205)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at org.hibernate.util.SerializationHelper$CustomObjectInputStream.resolveClass(SerializationHelper.java:263)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1575)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1624)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1323)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:210)
> and all other threads doing nothing
> INFO   | jvm 1    | 2007/11/30 16:56:44 |    java.lang.Thread.State: BLOCKED (on object monitor)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.lang.ClassLoader.loadClass(ClassLoader.java:295)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       - waiting to lock <0x00002aaab4095a68> (a org.apache.catalina.loader.StandardClassLoader)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1346)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1205)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at org.hibernate.util.SerializationHelper$CustomObjectInputStream.resolveClass(SerializationHelper.java:263)
> INFO   | jvm 1    | 2007/11/30 16:56:44 |       at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1575)
> (rest of stack trace identical to above)
> This can easily be worked around by setting the compatibility property 
>    -Dsun.lang.ClassLoader.allowArraySyntax=true
> however a) this workaround might not be around for long and b) most people will never find this bottleneck, therefore will not apply the workaround.
> For our case, we got a 35% performance increase just be setting this property (and not a single loadClass() or ZipFile.getEntry() in any thread dump any more).
> Cheers, Tom.

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the hibernate-issues mailing list