[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
| [eclipselink-dev] Moxy expensive classloader search when using elements with primitive types | 
Hi,
this post was originally sent to the users list. There was no response 
and it is probably more appropriate for the dev list, so moving here.
I analyzed a performance problem of an application using Moxy. It turned 
out that threads were blocking on the classloader lock. This was due to 
JaxbClassLoader frequently calling loadClass() on its parent loader.
The root cause was a combination of two factors:
- no reuse of the JAXBContext
- use of xsd:int (and other primitive types) as *element* types
What happens, is that JAXBContext was looking for xsd:int and that went 
to the JaxbClassLoader calling loadClass("int"). That type of course 
isn't known so the parent classloader had to search through all of its 
jars to check. In our case the search was further delegated from a web 
app classloader to the system classloader to the bootstrap classloader. 
The latter two do not have caches for not found resources, so each time 
a new JAXBContext tried to resolve "int", the search was done. Each of 
the classloaders involved ends the search with creating an (expensive) 
ClassNotFoundException. Since this takes quite some time, the 
classloader locks got contented and threads piled up.
Note that if you use xsd:int as the type of an *attribute*, this does 
not happen. Moxy will map that straight to "Integer" instead of 
searching for "int". Only when using xsd:int for an *element* that 
problem shows up. The problem also does not happen when using the JAXB 
reference implementation.
I'm not saying, that the final result is broken. After the CNFE from the 
parent classloader, Moxy finally maps e.g. an xsd:int element to the 
Java primitive int. I'm only saying that doing a classloader search for 
a primitive type is expensive and should not be done.
I know that this wouldn't have hurt so much, if we had reused the 
JAXBContext. Nevertheless I think that it would be easy to improve 
JaxbClassLoader. As a workaround we can use a mapping file to map the 
primitive types to the corresponding object types during xjc, but that 
should not be necessary.
I'll attach a simple example project, hopefully attachments are allowed 
here. It contains a README and you can simply run it with "ant" using 
Moxy 2.5.x. It contains a slightly patched version of JaxbClassLoader to 
make the CNFE from the parent classloader observable by output to 
STDOUT. It first runs the example using attributes - no primitives 
loading - then using elements showing the primitives loading and CNFE.
I'll also attach a draft patch for improving the JaxbClassLoader.
Regards,
Rainer
--- org/eclipse/persistence/internal/jaxb/JaxbClassLoader.java	2014-12-02 18:33:49.502368000 +0100
+++ org/eclipse/persistence/internal/jaxb/JaxbClassLoader.java	2014-12-02 18:34:08.808602000 +0100
@@ -89,6 +89,20 @@
 	
     public Class loadClass(String className) throws ClassNotFoundException {
         Class javaClass = null;
+        if (className.indexOf('.') == -1 &&
+            (className.equals("boolean") ||
+            className.equals("short") ||
+            className.equals("int") ||
+            className.equals("long") ||
+            className.equals("float") ||
+            className.equals("double") ||
+            className.equals("byte") ||
+            className.equals("char"))) {
+            javaClass = (Class)generatedClasses.get(className);
+            if (javaClass != null) {
+                return javaClass;
+            }
+        }
         try {
             javaClass = getParent().loadClass(className);
         } catch (ClassNotFoundException e) {
Attachment:
moxy-primitives-CNFE.tar.gz
Description: application/gzip