Не удалось сопоставить собственное выделение памяти (mmap) при использовании jdbc8.jar и клиента Oracle 18.

У меня есть java-приложение, которое извлекает большой xml из базы данных Oracle 11g версии 11.2.0.4.0 (используя Spring 4) и сохраняет их в файлах. У нас возникла проблема с извлечением данных, содержащих многобайтовые символы. В зависимости от того, где в xml находился мультибайт, он иногда делил мультибайт на 2 части. Похоже, проблема была связана с версией jdbc и установленным клиентом оракула. Поэтому мы перешли на клиент Oracle 18 и ojdb8.jar, оставив код нетронутым. Проблема с многобайтностью была решена, но вместо этого у нас появились проблемы с памятью, которых раньше не было. Ошибка, которую я получаю:

Недостаточно памяти для продолжения работы Java Runtime Environment.

Собственное распределение памяти (mmap) не смогло отобразить 256376832 байта для выделения зарезервированной памяти.

Я играл с параметрами команды java, но безрезультатно. Это то, что я запускаю: java -Dfile.encoding=UTF8 -Doracle.jdbc.timezoneAsRegion=false -Xmx10240m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -XX:NativeMemoryTracking=detail -XX:+StartAttachListener -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics

Уменьшение Xmx до 512 м закончилось нехваткой динамической памяти.

Я отслеживал память приложения, используя jcmd VM.native_memory baseline/summary.diff и GC.class_stats, и одним из самых больших потребителей памяти являются объекты String. Остальное я не мог понять.

sql это: ВЫБЕРИТЕ XML_DATA ИЗ таблицы, где....

Столбец xml_data определяется как: XML_DATA NOT NULL SYS.XMLTYPE STORAGE BINARY

сопоставление этого в java с oracle.xdb.XMLType:

public List<XMLType> extractXmlDataList(String sqlExtractionQuery, Key key) {
    MapSqlParameterSource namedSqlParams = createKeyParamMap(key);
    List<XMLType> dataList = namedParameterJdbcTemplate.queryForList(sqlExtractionQuery, namedSqlParams, XMLType.class);
    return dataList;
}


protected void extractXmlData(Key key) {
List<XMLType> xmlRecs = producerDao.extractXmlDataList(sqlExtractionQuery, patentKey);
    if (xmlRecs != null && xmlRecs.size() > 0) {
        for (XMLType xmlData : xmlRecs) {
            String xmlText = xmlData.getStringVal();
            //create nu.xom.Document
            Builder parser = new Builder();
            Document xmlDocument = parser.build(xmlText, null);
        }
    }       
}

Как переход на клиент Oracle 18 и jdbc8.jar мог так сильно повлиять на потребление памяти?

Почему вы загружаете 250 МБ напрямую в память? Я предлагаю использовать InputStream

Lino 22.05.2019 15:34

Не уверен, что понимаю, почему это поможет. В конце концов мне пришлось бы преобразовать InputStream в строку, чтобы создать XML-документ, не так ли?

HRaz 22.05.2019 16:10

В зависимости от того, что вы хотите делать с XML, вам почти никогда не придется считывать весь файл в память.

Lino 22.05.2019 16:14

В этом случае я должен прочитать все данные в память, по-другому не вижу.

HRaz 22.05.2019 16:18

(Дикое предположение, потому что я не знаком с Java) Есть ли какой-то размер предварительной выборки по умолчанию для нового клиента? Может быть, клиент пытается прочитать слишком много строк одновременно, и результаты большого столбца XML занимают всю память?

Jon Heller 23.05.2019 01:49
Основы программирования на Java
Основы программирования на Java
Java - это высокоуровневый объектно-ориентированный язык программирования, основанный на классах.
Концепции JavaScript, которые вы должны знать как JS программист!
Концепции JavaScript, которые вы должны знать как JS программист!
JavaScript (Js) - это язык программирования, объединяющий HTML и CSS с одной из основных технологий Всемирной паутины. Более 97% веб-сайтов используют...
1
5
884
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема с памятью была решена с помощью xmlserialize, а не объекта Oracle Java XMLType. Все еще использую клиент Oracle 18 и ojdbc8.jar. Больше никаких проблем с многобайтовым разделением UTF8.

Другие вопросы по теме