Java OutOfMemory в приложении с Hibernate, Quartz и и JavaMail - PullRequest
1 голос
/ 07 июля 2011

У меня есть веб-приложение, работающее на Tomcat 6, которое я создал с Netbeans 6.9.1 и его мастерами для классов Entity и персистентности. Он использует Hibernate, MySQL в качестве базы данных, Quartz для выполнения задач каждые 15 минут и JavaMail.

Спящая конфигурация выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8" ?> 
 <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
 <persistence-unit name="GVPU" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider> 
  <class>com.test.MyfirstEntity</class> 
  <class>com.test.MySecondEntity</class> 
  <exclude-unlisted-classes>true</exclude-unlisted-classes> 
 <properties>
  <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /> 
  <property name="hibernate.connection.username" value="root" /> 
  <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" /> 
  <property name="hibernate.connection.password" value="password" /> 
  <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/db" /> 
  <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" /> 
  <property name="hibernate.hbm2ddl.auto" value="update" /> 
  <property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider" /> 
  <property name="hibernate.c3p0.acquire_increment" value="1" /> 
  <property name="hibernate.c3p0.idle_test_period" value="300" /> 
  <property name="hibernate.c3p0.timeout" value="100" /> 
  <property name="hibernate.c3p0.max_size" value="100" /> 
  <property name="hibernate.c3p0.min_size" value="0" /> 
  <property name="hibernate.c3p0.max_statements" value="0" /> 
  </properties>
  </persistence-unit>
  </persistence>

Задача, созданная с помощью Quartz, которая запускается каждые 15 минут, проверяет учетную запись GMail с использованием JavaMail (с IMAP), извлекает все сообщения, обрабатывает их (ищет некоторую информацию) и сохраняет объекты с этой информацией в БД с использованием Hibernate , Затем он помечает все письма как удаленные, чтобы они не обрабатывались при следующем запуске.

Каждый раз, когда выполняется эта задача, она потребляет 10, 20, 50 МБайт в зависимости от того, сколько писем она обрабатывает. Я посмотрел на MySQL Administrator, и соединения с БД закрыты, когда не нужно. Но если я посмотрю на память процесса (на машине linux, на которой он работает), память увеличится, пока не достигнет предела, при котором загрузка ЦП составляет 100%, и Tomcat больше не отвечает.

Я несколько раз менял -Xms -Xmx и PermGem Size, чтобы попробовать разные решения, но он всегда достигает точки, когда система перестает работать и память не освобождается.

Есть идеи, где я могу начать искать эту проблему? Я назначил более 1,5 ГБ на виртуальную машину Java, и он также зависает, даже если он длится более суток.

Когда Tomcat и все приложение перестают работать, трассировка стека отсутствует.

Спасибо

Ответы [ 4 ]

2 голосов
/ 07 июля 2011

Присоедините jvisualvm в JDK, чтобы получить профилирование памяти.

Обратите внимание, что, насколько мне известно, JavaMail не эффективно обрабатывает большие вложения, и получающиеся в результате письма становятся еще больше. Следовательно, вы должны убедиться, что почта очищена из памяти перед обработкой следующего.

Я бы посоветовал вам установить локальный SMTP-сервер - это очень просто для большинства дистрибутивов Linux - и позволить вашему Java-приложению говорить об этом. Это сделает вашу задачу намного быстрее и освободит память.

Если вы продолжаете получать исключения OOM, рассмотрите возможность запуска отправки почты в отдельной JVM, чтобы она не влияла на остальную часть вашего приложения.

0 голосов
/ 07 июля 2011

Возможно, вы не закрываете соединения с базой данных должным образом. Это может привести к тому, что объекты останутся в памяти и не будут собирать мусор. Проверьте наличие потерянных соединений и зарегистрируйте их (в ваших конфигурациях c3p0). Однажды я столкнулся с подобной проблемой, и она свалилась из-за мошеннических подключений к базе данных.

0 голосов
/ 07 июля 2011

Как вы управляете сессиями Hibernate между запусками процесса?Вы уверены, что не храните все кэшированные объекты из всех предыдущих запусков вашего процесса в кеше сеанса Hibernate или в своем собственном кеше?

0 голосов
/ 07 июля 2011

Общий подход: получить дамп памяти и найти самые многочисленные объекты или самые большие объекты и посмотреть, не существуют ли они, но все еще существуют.Затем вы можете увидеть, какие объекты не позволяют собирать этот мусор (удерживая ссылки на мусор).

...