Entitymanager вызывает утечку памяти? - PullRequest
9 голосов
/ 01 апреля 2009

В моем приложении Java медленная утечка памяти. Мне было интересно, может ли это быть вызвано не всегда закрытием Entitymanager при использовании. Однако, используя myeclipse для генерации кода БД, я получаю такие методы:

public Meit update(Meit entity) {
    logger.info("updating Meit instance");
    try {
        Meit result = getEntityManager().merge(entity);
        logger.info("update successful");
        return result;
    } catch (RuntimeException re) {
        logger.error("update failed");
        throw re;
    }
}

Которые никогда не закрывают EntityManager. Учитывая, что это сгенерированный код, мне интересно, кто прав, я или IDE.

Ответы [ 4 ]

6 голосов
/ 12 февраля 2010

Как сказал @Ruggs, если вы сами управляете жизненным циклом EntityManager (вместо того, чтобы J2EE управлял сохранением контейнера CMP), вам необходимо закрыть EntityManager самостоятельно или хотя бы вызвать EntityManager.clear() для отсоединения сущностей. *

EntityManager - это легкий объект, поэтому вам не нужно просто иметь его, вы можете создать его для каждой транзакции и закрыть его после фиксации транзакции.

Все сущности, которые загружаются / сохраняются через EntityManager, остаются в памяти до тех пор, пока вы явно не отсоедините от них сущности (через EntityManager.detach() или EntityManager.clear() или EntityManager.close()). Так что лучше иметь недолговечных EntityManager. Если вы сохраняете 1000000 сущностей через один и тот же EntityManager, не отсоединяя их после получения OOME (не имеет значения, сохраняете ли вы каждую сущность в ее собственной EntityTransaction).

Это все объяснено в этом посте http://javanotepad.blogspot.com/2007/06/how-to-close-jpa-entitymanger-in-web.html.

В качестве примера (взятого из предыдущего поста), если вы хотите избежать «утечек памяти», вы должны сделать что-то вроде этого (если вы не используете CMP):

EntityManager em = emf.createEntityManager();

try {
  EntityTransaction t = em.getTransaction();
  try {
    t.begin();  
    // business logic to update the customer
    em.merge(cust);
    t.commit();
  } finally {
   if (t.isActive()) t.rollback();
  }
} finally {
  em.close();
}
1 голос
/ 01 апреля 2009

Проверьте, действительно ли это утечка

если это так, то получите Eclipse Memory Analyzer и проанализируйте его.

Сообщения в блоге здесь также могут быть полезны.

1 голос
/ 01 апреля 2009

Похоже, вы используете приложение, управляемое приложением EntityManager. Вам нужно будет самому закрыть EntityManager, это часть спецификации. Вам также необходимо закрыть EntityManagerFactory при завершении работы вашего веб-приложения.

Я бы рекомендовал использовать что-то вроде OpenEJB или Springframework для управления EntityManager / EntityMangerFactory за вас.

1 голос
/ 01 апреля 2009

Менеджеры сущностей, как правило, должны иметь тот же жизненный цикл, что и приложение, и не должны создаваться или уничтожаться по запросу.

Ваша «утечка памяти» может быть не чем иным, как кеширование JPA. Вы не говорите, каким провайдером JPA вы пользуетесь, но по опыту я знаю, что EclipseLink по умолчанию выполняет расширенное кэширование (что является частью предполагаемых преимуществ JPA и ORM в целом).

Как вы узнали, что у вас утечка памяти?

...