[
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