Hi all,
I have an application with Spring core 2.5.6, Spring-Hibernate3 2.0.8, deployed in Tomcat 6. The OutOfMemoryError appears after about 24 hours of operation.
When I dumped the heap, I saw that 80% of memory is going into SessionFactoryObjectFactory and an enormous FastHash of tens of thousands of entries.Code:java.lang.OutOfMemoryError: Java heap space at java.lang.StringCoding$StringDecoder.decode(StringCoding.java:133) at java.lang.StringCoding.decode(StringCoding.java:173) at java.lang.String.<init>(String.java:443) at org.postgresql.core.Encoding.decode(Encoding.java:181) at org.postgresql.core.Encoding.decode(Encoding.java:193) at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getString(AbstractJdbc2ResultSet.java:1893) at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getString(AbstractJdbc2ResultSet.java:2187) at org.apache.tomcat.dbcp.dbcp.DelegatingResultSet.getString(DelegatingResultSet.java:225) at org.hibernate.type.StringType.get(StringType.java:18) at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:163) at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:154) at org.hibernate.type.AbstractType.hydrate(AbstractType.java:81) at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2096) at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1380) at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1308) at org.hibernate.loader.Loader.getRow(Loader.java:1206) at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:580) at org.hibernate.loader.Loader.doQuery(Loader.java:701) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236) at org.hibernate.loader.Loader.loadCollection(Loader.java:1994) at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:36) at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:565) at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:60) at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1716) at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:344) at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86) at org.hibernate.collection.PersistentSet.toArray(PersistentSet.java:171) at java.util.Vector.addAll(Vector.java:830) at net.sourceforge.seqware.common.hibernate.FindAllTheFiles.filesFromIUS(FindAllTheFiles.java:109) at net.sourceforge.seqware.common.hibernate.FindAllTheFiles.filesFromSample(FindAllTheFiles.java:97) at net.sourceforge.seqware.common.hibernate.FindAllTheFiles.filesFromExperiment(FindAllTheFiles.java:77) at net.sourceforge.seqware.common.hibernate.FindAllTheFiles.filesFromStudy(FindAllTheFiles.java:69)
I googled and found this entry: http://forum.springsource.org/showth...ring-hibernate that gives some suggestions on how to fix the problem. Nothing I do seems to fix it though.
My application context is only being initialized once in a Singleton:
I suspect it has to do with the transaction management system. The Hibernate layer was built separately from the web app, so in order to do lazy loading, I bind the session to the current thread. I extend the following abstract class whenever I need to work with objects that are lazily loaded.Code:ApplicationContext appCtx = new ClassPathXmlApplicationContext("applicationContext.xml");
I tried to use getCurrentSession rather than getSession but it complained that I didn't have an open session. That led me down the path of trying to use OpenSessionInViewFilter. I put the following into my web.xml:Code:public abstract class InSessionExecutions { public void runInSessionCalculations() { SessionFactory sessionFactory = BeanFactory.getSessionFactoryBean(); Session session = null; try { session = bindSessionToThread(sessionFactory); hibernateCalls(); } finally { if (session != null) { unBindSessionFromTheThread(sessionFactory, session); } } } protected abstract void hibernateCalls(); public static Session bindSessionToThread(SessionFactory sessionFactory) { Session session = SessionFactoryUtils.getSession(sessionFactory, true); TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session)); return session; } public static void unBindSessionFromTheThread(SessionFactory sessionFactory, Session session) { session.flush(); TransactionSynchronizationManager.unbindResource(sessionFactory); SessionFactoryUtils.releaseSession(session, sessionFactory); } }
That didn't appear to do anything. I still got the same error. So I went back to using getSession.Code:<filter> <filter-name>openSessionInViewFilter</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>openSessionInViewFilter</filter-name> <servlet-name>/*</servlet-name> </filter-mapping>
Next I tried to use a separate session for each transaction. The code above reflects that. But since TransactionSynchronizationManager maps the session using the SessionFactory and there's only one of those, I can't have more than one request at the same time.
Here's a snippet of my applicationContext that is relevant to the question:
I'm not an expert in Hibernate or in Spring and I'm at a loss of where to go from here. Does anyone have any insights?Code:<!-- Hibernate SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"> <ref local="dataSource" /> </property> <property name="mappingResources"> <list> <value>net/sourceforge/seqware/common/model/Mappings.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop> <!-- <prop key="hibernate.show_sql">true</prop>--> <prop key="hibernate.default_entity_mode">pojo</prop> <prop key="hibernate.current_session_context_class">thread</prop> <!-- prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop --> </props> </property> </bean> <!-- Transaction manager for the Hibernate SessionFactory. --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> </bean>


Reply With Quote
