Lately I have been maintaining several Spring-MVC applications written from the ground up with Spring 3.1. They use the purely Java based configuration scheme that comes in version 3.1, Hibernate. The apps do not have the pattern of “an interface for every class” that some Spring apps have, so it proxies concrete classes using Cglib. When the apps are deployed to Tomcat, we do a full instance restart, but when developing inside of Eclipse JEE and the embedded Tomcat instance, after about 5 redeploys the apps will crash due to running out of perm gen space.

When we created these services, I relied heavily on several blog posts detailing how to do Spring without XML. One of these posts suggested setting up Hibernate like so:

@Bean
public AbstractSessionFactoryBean mySessionFactory() {
	AnnotationSessionFactoryBean b = new AnnotationSessionFactoryBean();
	b.setDataSource(dataSource);
	b.setPackagesToScan(new String[] { this.getClass().getPackage().getName() + ".model" });
	Properties hiberProps = new Properties();
	hiberProps.setProperty("hibernate.show_sql", Boolean.toString(hibernateShowSql));
	hiberProps.setProperty("hibernate.dialect", hibernateDialect);
	b.setHibernateProperties(hiberProps);
	return b;
}
@Bean
public AbstractPlatformTransactionManager transactionManager() {
	HibernateTransactionManager tm = new HibernateTransactionManager();
	tm.setSessionFactory(mySessionFactory().getObject());//Error is here
	return tm;
}

The problem seems to arise in transactionManager() – it calls mySessionFactory(), without using the actual bean. My understanding of Spring is still not the greatest, but even with all of the magic that Spring performs, I do believe this leaves two instances of AbstractSessionFactoryBean in memory – one directly in Spring’s context, the other hidden inside the HibernateTransactionManager. One of these two is not collected properly on a Tomcat redeploy, causing the entire classloader to get stuck in permgen.

Changing to the following has fixed the issue:

@Bean
public AbstractSessionFactoryBean paymentSessionFactory() {/* no change */}
@Bean
@Autowired //Added this
public AbstractPlatformTransactionManager transactionManager(AbstractSessionFactoryBean bean) {//Added parameter
	HibernateTransactionManager tm = new HibernateTransactionManager();
	tm.setSessionFactory(bean.getObject());//Changed this
	return tm;
}