Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-users] Moxy expensive classloader search when using elements with primitive types

Hi,

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


Back to the top