Сокращение объема памяти при использовании больших XML DOM в Java - PullRequest
6 голосов
/ 12 декабря 2011

Наше приложение должно принимать данные клиента, представленные в формате XML (несколько файлов), и анализировать их в нашем общем формате XML (один файл со схемой). Для этого мы используем инфраструктуру привязки данных Apache XMLBeans. Этапы этого процесса кратко описаны ниже.

Сначала мы берем необработанные объекты java.io.File, указывающие на клиентские XML-файлы на диске, и загружаем их в коллекцию. Затем мы перебираем эту коллекцию, создавая по одному файлу apache.xmlbeans.XmlObject. После того, как все файлы были проанализированы в XmlObjects, мы создаем 4 коллекции, содержащие отдельные объекты из интересующих нас XML-документов (для ясности, это не объекты ручной работы, а то, что я могу описать только как созданные объекты «прокси») с помощью структуры Apache XMLBeans). В качестве последнего шага мы затем перебираем эти коллекции для создания нашего XML-документа (в памяти) и затем сохраняем его на диск.

В большинстве случаев этот процесс работает нормально и может легко запускаться в JVM при наличии аргумента командной строки '-Xmx1500m'. Однако проблемы возникают, когда клиент получает «большие наборы данных». В данном случае большой размер - 123 МБ клиентского XML-файла, распределенного по 7 файлам. Такие наборы данных приводят к тому, что наши коллекции в коде заполняются почти 40 000 вышеупомянутых «прокси-объектов». В этих случаях использование памяти просто идет вверх. Я не получаю никаких исключений вне памяти программа просто зависает, пока не происходит сборка мусора, освобождая небольшой объем памяти, программа затем продолжает работу, использует это новое пространство и цикл повторяется. Эти сеансы синтаксического анализа в настоящее время занимают 4-5 часов. Мы стремимся свести это к минимуму в течение часа.

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

То, что я пробовал до сих пор

Вместо того чтобы хранить все 123 МБ клиентского xml в памяти, при каждом запросе данных загружайте файлы, находите данные и освобождайте ссылки на эти объекты. Похоже, что это уменьшает объем памяти, потребляемой во время процесса, но, как вы можете себе представить, количество времени, которое занимает постоянный ввод-вывод, устраняет выгоду от уменьшения занимаемой памяти.

Я подозревал, что проблема заключалась в том, что мы храним XmlObject [] для файлов XML на 123 МБ, а также коллекции объектов, взятых из этих документов (с использованием запросов xpath). Чтобы исправить это, я изменил логику так, чтобы вместо запросов к этим коллекциям документы запрашивались напрямую. Идея состоит в том, что ни в одном месте не существует 4 массивных списков с 10 тысячами объектов, а просто большой коллекцией объектов XmlObject. Похоже, что это вообще ничего не меняет, а в некоторых случаях увеличивает объем используемой памяти.

Теперь, цепляясь за соломинку, я подумал, что объект XmlObject, который мы используем для создания нашей xml в памяти перед записью на диск, становился слишком большим, чтобы поддерживать его вместе со всеми данными клиента. Однако выполнение некоторых запросов sizeOf к этому объекту показало, что его максимальный размер составляет менее 10 КБ. После прочтения того, как XmlBeans управляет большими объектами DOM, он, похоже, использует некоторую форму буферизированного средства записи и в результате довольно хорошо управляет этим объектом.

Так что теперь у меня нет идей;Нельзя использовать SAX-подходы вместо DOM-подходов, требующих большого объема памяти, так как нам требуется 100% клиентских данных в нашем приложении в любой момент времени, мы не можем отложить запрос этих данных до тех пор, пока они нам абсолютно не понадобятся, поскольку процесс преобразования требует много циклов ивремя ввода-вывода на диске не стоит сэкономленного места в памяти, и я не могу структурировать нашу логику таким образом, чтобы уменьшить объем пространства, занимаемого внутренними java-коллекциями.Мне здесь не повезло?Должен ли я просто согласиться с тем, что если я хочу проанализировать данные xml на 123 МБ в наш формат XML, я не могу сделать это с выделением памяти на 1500 м?Хотя 123Mb - это большой набор данных в нашем домене, я не могу представить, чтобы другим никогда не приходилось делать что-то подобное с Gb-данными за один раз.

Другая информация, которая может быть важной

  • Я использовал JProbe, чтобы попытаться выяснить, может ли это сказать мне что-нибудь полезное.В то время как я являюсь noob для профилирования, я пробежал их учебники по утечкам памяти и блокировкам потоков, понял их, и в нашем коде нет никаких утечек или узких мест.После запуска приложения с большим набором данных мы быстро видим форму типа «пильный диск» на экране анализа памяти (см. Прилагаемое изображение) с пространством PS Eden, занятым массивным зеленым блоком PS Old Gen. Это наводит меня на мысль, чтопроблема заключается в том, что пространство коллекций объектов занято не просто утечкой, а утечкой неиспользуемой памяти.

JProbe trace of memory usage during parsing of large dataset

  • Я работаю на64-битная платформа Windows 7, но она должна работать в 32-битной среде.

1 Ответ

3 голосов
/ 12 декабря 2011

Подход, который я выбрал бы, состоял в том, чтобы сделать два прохода для файлов, используя SAX в обоих случаях.

При первом проходе данные «перекрестной ссылки», необходимые для расчетов, анализируются в пользовательских объектах и ​​сохраняются в них Map с.Если данные «перекрестных ссылок» велики, обратите внимание на использование распределенного кэша (когерентность - это естественное совпадение, если вы начали с Map s).

Второй проход позволит проанализировать файлы и получить«перекрестные ссылки» данных для выполнения расчетов по мере необходимости, а затем записи выходного XML с использованием javax.xml.stream API.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...