Спящий режим вызывает исключение нехватки памяти при сохранении большого количества объектов

#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 и избавился от проблем с памятью. Я попытаюсь исследовать это дальше