I noticed the problem in this post
http://forum.hibernate.org/viewtopic.php?t=930270
But I found it is NOT a problem of Application Server. To prove this, I created two simple classes. "CallJunk" repeatedly creates a URLClassLoader , loads Junk and hibernate classes, and call Junk.main(). Junk.main() opens a session and closes it.
The CallJunk program grows 1-2 MB in each loop step and finally run out of memory.
I profiled with JProfiler, the URLClassLoader and hibernate classes are not GCed.
According to that post, I also tried upgrade CGLib to 2.2_beta1, no help; tried JDK1.5 and JDK1.4, no help; tried Introspector.flushCaches(), no help; tried hibernate.cglib.use_reflection_optimize=false, no help; my simple junk class does not use ThreadLocal.
Code:
package calljunk;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
public class CallJunk {
static String[] dum=new String[0];
static Class[] parameterTypes = new Class[]{dum.getClass()};
public static void main(String[] args)throws Exception {
URL[] urls = new URL[]{
new File("../junk/cglib-2.2_beta1.jar").toURL(),
new File("../junk/commons-collections-2.1.1.jar").toURL(),
new File("../junk/dom4j-1.6.1.jar").toURL(),
new File("../junk/ehcache-1.2.jar").toURL(),
new File("../junk/hibernate3.jar").toURL(),
new File("../junk/jta.jar").toURL(),
new File("../junk/postgresql-8.0-311.jdbc3.jar").toURL(),
new File("../junk/commons-logging-1.0.4.jar").toURL(),
new File("../junk/bin").toURL()
};
for (int i=0; i<1000; i++) {
System.out.println("No "+i+": ");
//System.in.read();
Class cls = new URLClassLoader(urls).loadClass("junk.Junk");
cls.getMethod("main", parameterTypes).invoke(null, new Object[]{dum});
}
}
}
package junk;
import java.beans.Introspector;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import javax.naming.InitialContext;
public class Junk {
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
public static void main(String[] args) throws Exception {
Configuration cfg = new Configuration();
SessionFactory sFactory = null;
try {
cfg.configure(CONFIG_FILE_LOCATION);
String sessionFactoryJndiName = cfg.getProperty(Environment.SESSION_FACTORY_NAME);
if (sessionFactoryJndiName != null) {
cfg.buildSessionFactory();
sFactory = (SessionFactory) (new InitialContext()).lookup(sessionFactoryJndiName);
} else {
sFactory = cfg.buildSessionFactory();
}
} catch (Exception e) {
throw new HibernateException("Could not initialize the Hibernate configuration");
}
Session s = sFactory.getCurrentSession();
s.close();
Introspector.flushCaches();
sFactory.close();
}
}