2012-04-17 75 views
8

我每天都會在我的應用程序的新版本中發生OutOfMemory錯誤。我們爲Tomcat分配了1.5 GB的堆。JPA休眠DBCP Tomcat OutOfMemory

使用Eclipse的內存分析器(http://www.eclipse.org/mat/)我得到了最短積累路徑下的以下

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 

這進一步檢查顯示了很多重複的字符串這是Hibernate查詢。在我的應用程序主屏幕上,我加載了一個文檔列表。查詢的副本在堆轉儲中存在8,241次。

我還注意到1 GB的堆包含在org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool中。此文檔查詢正在加載文檔二進制數據。它正在加載的文件大約是1MB。這讓我懷疑List沒有被垃圾收集器清理乾淨。我們將從查詢中刪除不必要的數據,但仍然關注對象是否在附近。

我正在使用JPA,Hibernate和Spring。我正在使用獲取文檔列表的方法使用@Transactional(readOnly=true)。這裏是我的數據源的Spring配置:

<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> 

我正在使用Tomcat提供連接池。這是我的配置:

<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"/> 

服務層有@Transactional。我的JPA查詢看起來像這樣:

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; 
    } 

我應該尋找什麼來幫助確定內存泄漏的根本原因?有沒有可能對此有貢獻的DBCP,Hibernate或Spring設置?有沒有什麼您在JPA查詢代碼中注意到可能有所貢獻?

+0

getEntityManager()如何實現?是注入了@PersistenceContext的EntityManager嗎? – samlewis 2012-04-17 18:32:29

+0

是的。 Spring正在注入,這不是在JavaEE服務器上運行。我們正在使用Tomcat。 – Allan 2012-04-17 18:51:42

回答

0

嘗試在從方法返回之前清除EntityManager緩存。首先調用EntityManager.flush()方法,然後清理()。如果您的EntityManager「長期」存在並且它被許多數據庫操作使用,這可能會有所幫助。

如果你使用Spring,你可以放棄使用Hibernate來解決有問題的情況,並使用普通的JDBC。 Spring爲我們提供了JDBCTemplate,使其可以輕鬆查詢並提供常見的事務管理接口,因此您可以將Hibernate操作與JDBC查詢混合使用。