Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA Hibernate DBCP Tomcat OutOfMemory

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?

like image 688
Allan Avatar asked Apr 17 '12 16:04

Allan


1 Answers

I would strongly recommend to use VisualVM or jProfiler to identify the leak. Its IMHO the easiest way.

like image 90
Roman K Avatar answered Oct 06 '22 01:10

Roman K