#java #hibernate #csv #heap-memory
#java #спящий режим #csv #куча-память
Вопрос:
В моем приложении я использую CSVReader amp; hibernate для импорта большого количества объектов (например, 1 500 000 или более) в базу данных из файла csv. Код выглядит следующим образом:
Session session = headerdao.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
int count = 0;
String[] nextLine;
while ((nextLine = reader.readNext()) != null) {
try {
if (nextLine.length == 23
amp;amp; Integer.parseInt(nextLine[0]) > lastIdInDB) {
JournalHeader current = parseJournalHeader(nextLine);
current.setChain(chain);
session.save(current);
count ;
if (count % 100 == 0) {
session.flush();
tx.commit();
session.clear();
tx.begin();
}
if (count % 10000 == 0) {
LOG.info(count);
}
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
tx.commit();
session.close();
С достаточно большими файлами (где-то около 700 000 строк) Я получаю исключение нехватки памяти (пространство кучи).
Похоже, что проблема каким-то образом связана с гибернацией, потому что, если я прокомментирую только строку session.save(current); она работает нормально. Если оно раскомментировано, диспетчер задач показывает постоянно увеличивающееся использование памяти javaw, а затем в какой-то момент синтаксический анализ становится очень медленным и происходит сбой.
parseJournalHeader()
ничего особенного не делает, он просто анализирует объект на основе String[]
, который выдает программа чтения csv.
Комментарии:
1. Похоже, вы поступаете правильно с очисткой сеанса, которая должна устранять проблемы с памятью… одним из возможных вариантов может быть кэш 2-го уровня, он не будет очищен session.clear. Каковы его настройки… возможно, установка CacheMode.GET?
2. Здесь может быть полезен сеанс без состояния. Ознакомьтесь с ограничениями сеансов без состояния здесь : docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate / … , и если они не являются проблемой в вашем случае использования, попробуйте использовать его (через SessionFactory.openStatelessSession())
Ответ №1:
Сессия фактически сохраняет объекты в кэше. Вы делаете правильные вещи для работы с кэшем первого уровня. Но есть и другие вещи, которые препятствуют сборке мусора.
Попробуйте вместо этого использовать StatelessSession.
Комментарии:
1. Я пытался использовать StatelessSession, но с теми же результатами. Изучение дампа с помощью Eclipse Memory Analyzer показывает мне, что 6 «com.mysql.jdbc.jdbc4preparredstatement» являются главными подозреваемыми в утечке. Они потребляют практически всю память. Говорит ли это что-нибудь о проблеме?
2. Похоже, проблема каким-то образом связана с c3p0, кэширующим инструкции. Я удалил конфигурацию c3p0 из hibernate.cfg и избавился от проблем с памятью. Я попытаюсь исследовать это дальше