Details
Description
We have embedded Camel in an EAR that we deploy to Weblogic. The Camel context is configured via Spring:
<camelContext id="camel" handleFault="true" autoStartup="{{autoStartup}}" xmlns="http://camel.apache.org/schema/spring"> <contextScan /> <jmxAgent id="camelAgent" createConnector="true" registryPort="{{jmxPort}}" /> </camelContext>
You can see that we create a JMX connector to allow for remote management.
However, we have run into PermGen space issues, because our application is leaking class loaders when the application is undeployed or redeployed.
After digging around (and addressing some Jasper Reports ThreadLocal sloppiness), it appears that the only issue left is that the sun.rmi.transport.ObjectTable class maintains a static reference to all available RMI targets. Unfortunately, one of these targets is the JMX connector created by Camel, which was obviously loaded via our application's classloader.
Thus, ObjectTable has a static reference to the Camel JMX RMI target, which has a reference to the app's class loader, which in turn has references to all classes loaded (and generated) for that single deployment of the application – and none of these classes can be GC'ed.
After digging through the code for Camel's DefaultManagementAgent, I'm inclined to believe that the fix is fairly simple:
- Update createJmxConnector(String) to cache the reference to the created Registry in an instance variable.
- Update doStop() to check if we have a cached Registry instance, and if we do, call UnicastRemoteObject.unexportObject(registry, true);
Some app servers have workarounds for this sort of leak (see "RMI targets" in Table 1 at [1]), but Weblogic doesn't seem to.
I'll also attach a screenshot of the memory analysis (more info at [2]).