2012-04-17 33 views
8

Otrzymuję codzienne błędy OutOfMemory w nowej wersji mojej aplikacji. Mamy 1,5 GB sterty przydzielonej dla Tomcat.JPA Hibernate DBCP Tomcat OutOfMemory

Korzystanie z pamięci analizatora Eclipse (http://www.eclipse.org/mat/) Mam następujący pod najkrótszej drodze akumulacji

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 

Ponadto kontrola ta pokazuje wiele zduplikowanych ciągów, które Hibernate zapytaniami. Na ekranie głównym aplikacji ładuję listę dokumentów. Duplikat zapytania istnieje 8 241 razy w zrzucie sterty.

Zauważyłem również, że 1 GB sterty jest zawarte w org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool. To zapytanie do dokumentu ładowało dane binarne dokumentu. Obciążany dokument wynosi około 1 MB. To sprawia, że ​​podejrzewam, że lista nie jest czyszczona przez garbage collectora. Usuniemy niepotrzebne dane z zapytania, ale nadal mnie niepokoją, że obiekty się kręcą.

Używam JPA, hibernacji i wiosny. Używam @Transactional(readOnly=true) w metodzie, która pobiera listę dokumentów. Oto moja konfiguracja Spring dla źródła danych:

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

Używam Tomcat do zapewnienia połączenia puli. Oto moja konfiguracja:

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

Warstwa usług ma wartość @Transactional. Moja zapytań JPA wygląda następująco:

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

Co należy szukać, aby pomóc zidentyfikować przyczynę wycieku pamięci? Czy są jakieś ustawienia DBCP, Hibernate lub Spring, które mogą się do tego przyczynić? Czy jest coś, co można zauważyć w kodzie zapytań WZP, który może się przyczyniać?

+0

W jaki sposób implementuje się getEntityManager()? czy EntityManager został wprowadzony z adnotacją @PersistenceContext? – samlewis

+0

Tak. Wiosna wstrzykuje, to nie działa na serwerze JavaEE. Używamy Tomcat. – Allan

Odpowiedz

0

Spróbuj wyczyścić pamięć podręczną EntityManager przed powrotem z metody. Najpierw wywołaj metodę EntityManager.flush(), a następnie clean(). To może pomóc, jeśli twój EntityManager "żyje" długo i jest używany przez wiele operacji na bazach danych.

Jeśli używasz Spring, możesz zrezygnować z używania Hibernate w przypadku problematycznych sytuacji i przejść z prostym JDBC. Spring daje nam JDBCTemplate do łatwej pracy z zapytaniami i zapewnia również wspólny interfejs do zarządzania transakcjami, dzięki czemu możesz łączyć operacje Hibernate z zapytaniami JDBC.

1

Zdecydowanie zaleca się użycie VisualVM lub jProfiler w celu zidentyfikowania wycieku. Jego IMHO jest najprostszym sposobem.

Powiązane problemy