Недостаточно памяти при загрузке объектов Java - PullRequest
5 голосов
/ 03 июня 2010

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

Если у меня есть такой код:

MyEntity myEntity;
for (Object id: someIdList) {
   myEntity = find(id); 
   // do something basic with myEntity
}

И метод find () является стандартным методом, связанным с EntityManager:

public MyEntity find(Object id) {
    return em.find(mycorp.ejb.entity.MyEntity.class, id);
}

Этот код работал пару недель назад и отлично работает, если в базе данных меньше элементов. В результате возникает ошибка:

java.lang.OutOfMemoryError: превышен лимит накладных расходов GC

Исключение исходит от oracle toplink, вызывающего некоторые методы oracle jdbc.

Цикл существует, потому что EJBQL, такой как «select object (o) from MyEntity as o», будет перегружать сервер приложений при большом количестве записей.

Ответы [ 2 ]

9 голосов
/ 03 июня 2010

Этот код работал пару недель назад и отлично работает, если в базе данных меньше элементов. В результате возникает ошибка: java.lang.OutOfMemoryError: GC overhead limit exceeded

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

Если вам действительно нужно что-то сделать со всеми вашими сущностями, вам нужно позвонить flush() сначала , чтобы отправить все изменения в базу данных и , а затем clear() очистить постоянный контекст и регулярно освобождать память:

int i = 0;
for (Object id: someReallyBigIdList) {
    myEntity = find(id); 
    // do something basic with myEntity
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of DML operations and release memory:
        em.flush();
        em.clear();
    }
    i++;
}

Вызов clear() приводит к отсоединению всех управляемых объектов. Изменения, внесенные в объекты, которые не были сброшены в базу данных, не будут сохранены . Отсюда необходимость flush() сначала изменений .

4 голосов
/ 03 июня 2010

Проблема в том, что если вы делаете цикл, вы просто запрашиваете одну сущность за другой, но на нее все еще ссылаются в вашем EntityManager. Вы должны либо

  • clear () entityManager или
  • удалить сущность из нее (забыл, как была вызвана функция для этого).

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

...