JPA OneToMany — итерация по каскадным объектам и сборщику мусора

#java #jpa #garbage-collection #one-to-many

#java #jpa #сбор мусора #один ко многим

Вопрос:

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

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

Если я повторяю таким образом:

 for (Question q: quiz.getQuestions()) // triggers lazy loading of all questions of the quiz
{
    for(Answer a: q.getAnswers()) // triggers lazy loading of all answers of the question
    {
        longReadOnlyProcessingOfAnswer(a);
    }
}
 

После каждой итерации ответов они мне больше не нужны, но они все еще находятся в памяти, и GC не собирается их уничтожать.
К концу этого долгого выполнения тест со всеми вопросами и всеми ответами будет потреблять много памяти (десятки мегабайт)

Есть ли способ избавиться от ненужных объектов в памяти, сохранив этот ленивый подход к загрузке? Или я должен переключиться на получение ответов непосредственно из базы данных?

Комментарии:

1. Ну, если мы предположим, что a и q являются списками, вы можете удалить объекты из списка после того, как закончите с ними, что, предположительно, сделает их пригодными для gc. Однако отложенная загрузка может очень усложнить ситуацию, поскольку обычно создаются прокси-классы. Я пытаюсь удалить отложенную загрузку.

Ответ №1:

Просто задавайте вопросы один за quiz.getQuestions() другим. Как только вы закончите обработку ответов на конкретный вопрос, выполните EntityManager.flush() синхронизацию изменений, а затем EntityManager.detach(question) удалите question из контекста сохранения. Убедитесь, что у вас есть cascade = DETACH поверх Question.answers . Это должно сделать обработанные Question s вместе с их Answer s подходящими для GC.

(Я предполагаю Quiz.questions , что это не сторона-владелец связи между двумя объектами)

Вы также можете попробовать извлекать s пакетами, используя запрос, обрабатывать их, очищать, а затем очищать после каждого пакета. Question EntityManager Это позволит вам легко настроить размер пакета для оптимальной производительности.