2010-06-18 3 views
5

Приведенные ниже функции кода, но Hibernate никогда не отпускает свой захват какого-либо объекта. Вызов session.clear() вызывает исключения, связанные с получением связанного класса, а вызов session.evict(currentObject) до извлечения следующего объекта также не освобождает память. В конце концов я исчерпываю пространство кучи.Спящий режим: Пройдите миллионы строк и не просачивайте память

Проверка моих кучи кучи, StatefulPersistenceContext - это корень сборщика мусора для всех ссылок, указывающих на мои объекты.

public class CriteriaReportSource implements JRDataSource { 

    private ScrollableResults sr; 
    private Object currentObject; 
    private Criteria c; 
    private static final int scrollSize = 10; 
    private int offset = 1; 

    public CriteriaReportSource(Criteria c) { 
     this.c = c; 
     advanceScroll(); 
    } 

    private void advanceScroll() { 
//  ((Session) Main.em.getDelegate()).clear(); 
     this.sr = c.setFirstResult(offset) 
        .setMaxResults(scrollSize) 
        .scroll(ScrollMode.FORWARD_ONLY); 
     offset += scrollSize; 
    } 

    public boolean next() { 
     if (sr.next()) { 
      currentObject = sr.get(0); 
      if (sr.isLast()) { 
       advanceScroll(); 
      } 
      return true; 
     } 

     return false; 
    } 

    public Object getFieldValue(JRField jrf) throws JRException { 
     Object retVal = null; 
     if(currentObject == null) { return null; } 
     try { 
      retVal = PropertyUtils.getProperty(currentObject, jrf.getName()); 
     } catch (Exception ex) { 
      Logger.getLogger(CriteriaReportSource.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     return retVal; 
    } 
} 
+0

Я видел примеры этого в [Hibernate reference] (http://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html#batch-update), однако, там 'session.flush()' вызывается до 'session.clear()'. Не могли бы вы попробовать, имеет ли это значение? –

+0

Что это за база данных? Не все поддерживают истинную прокрутку курсора. Кроме того, я не вижу, чтобы вы закрывали ScrollableResults. –

+0

Я использую MySQL. –

ответ

1

Я думаю, что одна из моих проблем было то, что

if (sr.isLast()) { 
    advanceScroll(); 
    //... 

в сочетании с

((Session) Main.em.getDelegate()).clear(); 
//Also, "Main.em.clear()" should do... 

в результате промывки д atabase один запуск слишком рано. Это стало причиной исключений в отношении коллекций. Коллекции нельзя обрабатывать в StatelessSession, так что это вне таблицы. Я не знаю, почему session.evict(currentObject) не работает, когда Session.clear() действительно работает, но на этот раз мне придется его обрабатывать. Я подброшу ответы на вопрос, кто может это понять.

Итак, на данный момент у нас есть ответ. Требуется ручное окно прокрутки, закрытие прокручиваемых результатов не помогает, и мне нужно правильно запустить Session.clear().

+0

Это должно внести изменения в вопрос, а не как ответ. –

+1

Почему? Это успешно решает мою проблему. Пока он задает вопрос о Session.evict, который я мог бы переместить, это ответ. –

0

Пара вещей, которые я хотел бы предложить:

Попробуйте позвонить setCacheMode(CacheMode.IGNORE) по критериям, прежде чем открыть его.

В способе advanceScroll() добавьте if (sr != null) sr.close();, чтобы предыдущие прокручиваемые результаты были закрыты, прежде чем выполнять повторное назначение на новое.

Один вопрос: в чем причина вызова setMaxSize(), а затем отслеживания смещения и повторного открытия прокручиваемых результатов, почему бы просто не сделать это?

public CriteriaReportSource(Criteria c) { 
    this.c = c; 
    this.sr = c.setCacheMode(CacheMode.IGNORE) 
       .scroll(ScrollMode.FORWARD_ONLY); 
} 


public boolean next() { 
    if (sr.next()) { 
     currentObject = sr.get(0); 
     return true; 
    } 
    return false; 
} 
+0

Ни один из предложений в этом ответе не работал, к сожалению. setMaxSize() и такие были попытки решить проблему, контролируя окно того, что было запрошено. С или без них память продолжает расти. Попытка sr.close() также была бесплодной. –

+0

Жаль услышать это. Дайте StatelessSession, о котором говорил Паскаль, это может быть вашим лучшим выбором. –

3

Не использовать сеансный здесь, это просто не правильный инструмент для ходить миллионы строк и построить отчет. Вместо этого используйте The StatelessSession interface.

При использовании MySQL Connector/J, даже этого не достаточно, то необходимо также победить внутреннюю буферизацию сделано драйвером JDBC, с this:

Query query = session.createQuery(query); 
query.setReadOnly(true); 
// MIN_VALUE gives hint to JDBC driver to stream results 
query.setFetchSize(Integer.MIN_VALUE); 
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY); 
// iterate over results 
while (results.next()) { 
    Object row = results.get(); 
    // process row then release reference 
    // you may need to evict() as well 
} 
results.close(); 
+1

В настоящее время использование StatelessSession решает проблему памяти, но вызывает все ад, когда к ним присоединяются ассоциированные соединения OneToMany (ленивая загрузка). Вид интересной победы. Какие-либо предложения, когда я иду на тестирование, если это требует отгрузка? –

+0

Выключает StatelessSession не может обрабатывать коллекции. Я нашел способ использовать Stateful и контролировать свою память. См. Мой ответ на мой вопрос. –

Смежные вопросы