2012-04-17 2 views
8

Я получаю ежедневные ошибки OutOfMemory в новой версии моего приложения. У нас есть 1.5 ГБ кучи, выделенной для Tomcat.JPA Hibernate 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 ГБ кучи содержится в org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool. Этот запрос документа загружал двоичные данные документа. Документ, который загружается, составляет около 1 МБ. Это заставляет меня подозревать, что список не очищается сборщиком мусора. Мы удалим ненужные данные из запроса, но мне все же приходится беспокоиться о том, что объекты торчат.

Я использую 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()? является EntityManager, введенный аннотацией @PersistenceContext? – samlewis

+0

Да. Spring впрыскивает, это не работает на сервере JavaEE. Мы используем Tomcat. – Allan

ответ

0

Попробуйте очистить кеш-память EntityManager до того, как вы вернетесь из метода. Сначала вызовите метод EntityManager.flush(), а затем clean(). Это может помочь, если ваш EntityManager «живет» долго и используется многими операциями с базой данных.

Если вы используете Spring, вы можете отказаться от использования Hibernate для проблемной ситуации и пойти с простым JDBC. Spring дает нам возможность JDBCTemplate легко работать с запросами и обеспечивает также общий интерфейс управления транзакциями, поэтому вы можете смешивать операции Hibernate с запросами JDBC.

1

Я бы рекомендовал использовать VisualVM или jProfiler для идентификации утечки. Его ИМХО - самый простой способ.