Избегайте фрагментации памяти при выделении большого количества массивов в Java

Я разрабатываю приложение в Java, который работает на устройствах Windows Mobile. Для достижения этого, мы использовали JVM Esmertec JBed, которая не прекрасна, но мы застреваем с нею на данный момент. Недавно мы получали жалобы от клиентов о OutOfMemoryErrors. После большой игры вокруг с вещами я обнаружил, что устройство имеет много свободной памяти (приблизительно 4 МБ).

OutOfMemoryErrors всегда происходят в той же точке в коде, и это при расширении StringBuffer для добавления некоторых символов к нему. После добавления некоторого входа вокруг этой области я нашел, что мой StringBuffer имел приблизительно 290 000 символов в нем со способностью приблизительно 290 500. Стратегия расширения внутреннего символьного массива состоит в том, чтобы просто удвоить размер, таким образом, это попыталось бы выделить массив приблизительно 580 000 символов. Я распечатал использование памяти в это время также и нашел, что оно использовало приблизительно 3.8 МБ общего количества приблизительно 6.8 МБ (хотя я видел, что общая доступная память время от времени повышается приблизительно до 12 МБ, таким образом, существует много комнаты для расширения). Таким образом, это в этой точке, что приложение сообщает о OutOfMemoryError, который не имеет большого количества смысла, данного, насколько там все еще свободно.

Я начал думать об операции приложения до этой точки. В основном то, что происходит, я анализирую использование XML-файла MinML (маленький Синтаксический анализатор Саксофона XML). Одно из полей в XML имеет о 300k символах в нем. Синтаксический анализатор передает данные потоком из диска, и по умолчанию это загружает только 256 символов за один раз. Таким образом, когда это достигает рассматриваемого поля, синтаксический анализатор назовет 'символы ()' методом обработчика более чем 1 000 раз. Каждый раз это создаст новый символ [] содержание 256 символов. Обработчик просто добавляет эти символы к StringBuffer. Начальный размер по умолчанию StringBuffer - только 12, поэтому поскольку символы добавляются к буферу, он оказывается перед необходимостью расти неоднократно (каждый раз создавая новый символ []).

Мое предположение от этого было то, что возможно что, в то время как существует достаточно свободной памяти, так как предыдущий символ [] s может быть собран "мусор", возможно, нет никакого непрерывного блока памяти, достаточно большого для установки новому массиву, который я пытаюсь выделить. И возможно JVM не достаточно умна для расширения размера "кучи", потому что это глупо и думает, что нет никакой потребности потому что, по-видимому, существует достаточно свободной памяти.

Таким образом, мой вопрос: кто-либо имеет опыт этой JVM и мог бы быть в состоянии окончательно подтвердить или опровергнуть мои предположения о выделении памяти? И также, у кого-либо есть какие-либо идеи (предполагающий, что мои предположения корректны) о том, как улучшить выделение массивов так, чтобы память не становилась фрагментированной?

Примечание: вещи я уже попробовал:

  • Я увеличил начальный размер массива StringBuffer и меня increaed размер чтения синтаксического анализатора так, чтобы он не должен был создавать столько массивов.
  • Я изменил стратегию расширения StringBuffer так, чтобы, как только это достигло порога определенного размера, который это только развернет на 25%, а не 100%.

Выполнение обеих из этих вещей помогло немногому, но поскольку я увеличиваю размер данных XML, входящих, я все еще получаю OutOfMemoryErrors в довольно низком размере (приблизительно 350 КБ).

Другая вещь добавить: все это тестирование было выполнено на устройстве с помощью рассматриваемой JVM. Если я выполняю тот же код рабочего стола с помощью Java SE 1,2 JVM, у меня нет проблем, или по крайней мере я не получаю проблему, пока мои данные не достигают приблизительно 4 МБ в размере.

Править:

другая вещь, которую я только что попробовал, который помог немного, я установил Xms на 10M. Таким образом, это заканчивает проблему JVM, не расширяющей "кучу", когда она должна и позволять мне обрабатывать больше данных, прежде чем ошибка произойдет.

13
задан DaveJohnston 15 January 2010 в 11:12
поделиться