Glassfish + Hibernate = Memory Leak, and a Workaround
Our project setup:
- Glassfish 3.0.1
- Hibernate 3.5.3 bundled in the WAR
- Eclipse 3.5.2 with Glassfish plug-in
Editing and saving a file in Eclipse causes the WAR to be redeployed to the running Glassfish instance. After 5 or 6 edit-redeploy cycles, Glassfish throws OutOfMemory exceptions, usually you have to kill Glassfish and restart Eclipse to continue working.
I first wrote about the problem here
and filed a bug report
The same effect occurs when redeploying the WAR outside of Eclipse using asadmin redeploy, so Eclipse is not a contributing factor.
Run Hibernate using cglib as bytecode provider instead of the default javassist. To do so, set the system property
in your domain.xml. Setting this property in persistence.xml has no effect.
The root cause:
There is an incorrect usage of a WeakHashMap in javassist which is bundled deep down in Glassfish within Weld, holding strong references to old WebappClassLoaders. For some reason, weld-osgi-bundle.jar exports the package javaassist.util.proxy in its OSGi manifest and does not keep its copy of javassist fully private. This is bound to cause problems is OSGi land: either you keep a dependency fully private, or you import it from another bundle. Partially exporting it creates a problem for any other bundle requiring the same dependency.
Our WAR includes hibernate.jar and javassist.jar, but due to parent classloader delegation, Hibernate ends up with the javassist.util.proxy.ProxyFactory exported by Weld, leaving all the dangling webapp classloader references in the container.