I am getting daily OutOfMemory errors in a new version of my application. We have 1.5 GB of heap allocated for Tomcat.
Using the Eclipse Memory analyzer (http://www.eclipse.org/mat/) I got the following under the Shortest Accumulation Path
org.apache.tomcat.dbcp.pool.impl.CursorableLinkedList$Listable @ 0xa1566cc8
_head org.apache.tomcat.dbcp.pool.impl.CursorableLinkedList @ 0xa1566ca8
_pool org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool @ 0xa1566c38
connectionPool org.apache.tomcat.dbcp.dbcp.BasicDataSource @ 0xa1566980
dataSource org.springframework.orm.jpa.JpaTransactionManager @ 0xa0b01760
<Java Local> java.lang.Thread @ 0xa4005900 ajp-8141-5 Thread
Further inspection of this shows a lot of duplicate strings which are Hibernate queries. On my applications home screen, I load a list of documents. A duplicate of the query exists 8,241 times in the heap dump.
I also noticed that 1 GB of the heap is contained in org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool. This document query was loading the document binary data. The document that it is loading is around 1MB. This makes me suspect that the List is not getting cleaned up by the garbage collector. We will be removing unnecessary data from the query but it still concerns me that objects are sticking around.
I am using JPA, Hibernate and Spring. I am using @Transactional(readOnly=true)
on the method that get the document list. Here is my Spring config for the data source:
<jee:jndi-lookup jndi-name="jdbc/MyDB" id="myDataSource"/>
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="persistenceUnitName" value="WebPU"/>
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" />
</property>
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="SQL_SERVER" />
<property name="showSql" value="false" />
<property name="generateDdl" value="false" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
I am using Tomcat to provide the connection pooling. Here is my configuration:
<Resource auth="Container" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" initialSize="20"
logAbandoned="true" maxActive="100" maxIdle="30" maxWait="10000" name="jdbc/MyDB" password="pass" poolPreparedStatements="true" removeAbandoned="true" removeAbandonedTimeout="30"
type="javax.sql.DataSource"
url="jdbc:sqlserver://devmssql;databaseName=MY_DEV;responseBuffering=adaptive;port=1444"
username="user"/>
The service layer has the @Transactional. My JPA Query looks like this:
public List<Document> getDocs(int cId, int lId, int ldId) {
CriteriaBuilder queryBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Document> select = queryBuilder.createQuery(Document.class);
Root<Document> from = select.from(Document.class);
select.where(
queryBuilder.and(queryBuilder.equal(from.get(Document_.cId), cId),
queryBuilder.equal(from.get(Document_.lId), lId),
queryBuilder.equal(from.get(Document_.ldId), ldId)));
TypedQuery<Document> tq = getEntityManager().createQuery(select);
final List<Document> rl = tq.getResultList();
return rl;
}
What should I be looking for to help identify the root cause of the memory leak? Are there ay DBCP, Hibernate or Spring settings that could be contributing to this? Is there anything you notice in the JPA query code that might be contributing?
I would strongly recommend to use VisualVM or jProfiler to identify the leak. Its IMHO the easiest way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With