Странное поведение Java -Xmx на большом количестве оперативной памяти - PullRequest
7 голосов
/ 08 марта 2011

Вы можете контролировать максимальный размер кучи в Java, используя опцию -Xmx.

Мы наблюдаем странное поведение в Windows с этим переключателем. Мы запускаем несколько очень мощных серверов (например, оперативная память 196 ГБ) Версия Windows - Windows Server 2008R2

Версия Java 1.6.0_18, 64-битная (очевидно).

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

Итак, мы написали простую программу, которая будет выделять байтовый массив размером 1 ГБ при каждом нажатии клавиши ввода и инициализировать байтовый массив случайными значениями (чтобы предотвратить сжатие памяти и т. Д.).

По сути, происходит следующее: если мы запустим программу с параметром -Xmx35000m (примерно 35 ГБ), мы получим исключение нехватки памяти при достижении 25 ГБ пространства процесса (для измерения используется диспетчер задач Windows). Мы добились этого после распределения 24 ГБ блоков по 1 ГБ, кстати, чтобы проверить.

Простое указание большего значения для опции -Xmx приводит к тому, что программа прекрасно работает с большим количеством оперативной памяти.

Итак, что происходит? -Xmx просто "выключен". Кстати: нам нужно указать -Xmx55000m, чтобы получить пространство процесса 35 ГБ ...

Есть идеи о том, что происходит?

Является ли это ошибкой в ​​Windows JVM?

Безопасно ли просто установить параметр -Xmx больше, даже если между параметром -Xmx и тем, что происходит в процессе, есть разрыв?

Ответы [ 5 ]

8 голосов
/ 08 марта 2011

Теория # 1

Когда вы запрашиваете кучу 35 Гбайт с использованием -Xmx35000m, вы на самом деле говорите, что общий объем пространства, используемого для кучи, составляет 35 Гб.Но общее пространство состоит из пространства Tenured Object (для объектов, переживших несколько циклов GC), пространства Eden для вновь создаваемых объектов и других пространств, в которые объекты будут копироваться во время сборки мусора.

Проблема заключается в том,что некоторые пробелы не используются и не могут быть использованы для размещения новых объектов.Таким образом, по сути, вы «теряете» значительный процент своих 35 ГБ на накладные расходы.

Существуют различные опции -XX, которые можно использовать для изменения размеров соответствующих пространств и т. Д. Вы можете попробовать поиграться с нимичтобы увидеть, если они имеют значение.Обратитесь к этому документу для получения дополнительной информации.(Обычно используемые параметры настройки GC перечислены в разделе 8. Параметр -XX: NewSpace выглядит многообещающе ...)


Theory # 2

Это может происходить из-за того, что вывыделяя огромные объекты.IIRC, объекты выше определенного размера могут быть размещены непосредственно в пространстве объекта аренды.В вашем (очень искусственном) тесте это может привести к тому, что JVM не помещает вещи в пространство Eden и, следовательно, может использовать меньше всего пространства кучи, чем обычно.

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


Вот некоторые другие теории, которые я бы не учел:

  • «Вы работаете в рамках ограничений, установленных ОС».Я бы проигнорировал это, поскольку вы сказали, что вы можете значительно увеличить использование памяти, увеличив параметр -Xmx ...

  • «Диспетчер задач Windows сообщает фиктивные числа».Я бы обесценил это, потому что указанные цифры примерно соответствуют 25 ГБ, которые, по вашему мнению, удалось выделить вашему приложению.

  • «Вы теряете место для других вещей, например, кучи permgen».AFAIK, размер кучи permgen контролируется и учитывается независимо от «нормальных» куч.Другое использование памяти без кучи является либо постоянным (для приложения), либо зависит от выполнения определенными действиями приложения.

  • «Вы страдаете от фрагментации кучи».Все сборщики мусора JVM являются «копирующими сборщиками», и у этого семейства сборщиков есть свойство автоматически сжимать узлы кучи.

  • «Ошибка JVM в Windows».Очень маловероятно.В Windows должно быть несколько десятков тысяч 64-битных Java-приложений, которые максимизируют размер кучи.Кто-то еще заметил бы ...


Наконец, если вы НЕ делаете этого, потому что ваше приложение требует, чтобы вы выделяли память большими кусками и зависали "навсегда""... есть хороший шанс, что вы гоняетесь за тенями.«Нормальное» приложение с большой памятью такого не делает, а JVM настроена на нормальные приложения ... не аномальные.

И если ваше приложение действительно ведет себя таким образом, прагматичнорешение состоит в том, чтобы просто установить параметр -Xmx ... больше и беспокоиться, только если вы начнете сталкиваться с проблемами на уровне ОС.

2 голосов
/ 08 марта 2011

пытались ли вы включить подробный вывод для GC, чтобы выяснить, почему происходит сбой последнего выделения.это связано с тем, что ОС не выделяет кучу за пределами 25 ГБ для собственного процесса JVM, или это происходит из-за того, что сборщик мусора устанавливает какой-то предел максимального объема памяти, которым он может управлять.Я бы порекомендовал вам также подключиться к процессу командной строки с помощью jconsole, чтобы увидеть, каково состояние кучи непосредственно перед ошибкой выделения.Также такие инструменты, как проводник процессов sysinternals, могут дать более подробную информацию о том, где происходит сбой, если он происходит в процессе jvm.

Поскольку процесс умирает на 25 ГБ, и у вас есть сборщик поколений, может быть, остальные поколенияпотребляют 10 ГБ.Я бы порекомендовал вам установить JDK 1.6_u24 и использовать jvisualvm с плагином visualGC, чтобы увидеть, что делает GC, особенно с учетом размера всех поколений, чтобы увидеть, как кучи 35 ГБ разделяется на различные области памяти GC / VM.менеджер.

см. эту ссылку, если вы не знакомы с поколением GC http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html#generation_sizing.total_heap

2 голосов
/ 08 марта 2011

Чтобы понять, что именно вы измеряете, вы должны использовать несколько различных инструментов:

  1. Диспетчер задач Windows (я знаю только Windows XP, но до меня дошли слухи, что диспетчер задач с тех пор улучшился.)
  2. procexp и vmmap от Sysinternals
  3. jconsole от JVM (вы используете Sun Oracle HotSpot JVM, не так ли?)

Теперь вы должны ответить на следующие вопросы:

  • Что jconsole говорит об используемом размере кучи? Чем это отличается от procexp?
  • Изменится ли значение из procexp, если вы заполните байтовые массивы ненулевыми числами вместо того, чтобы хранить их в 0?
0 голосов
/ 08 марта 2011

Память, отображаемая диспетчером задач Windows, представляет собой общую память, выделенную процессу, которая включает в себя память для кода, стека, perm gen и heap. Объем памяти, который вы измеряете с помощью программы click, - это объем кучи, доступной jvm для запуска программ jvm. Естественно, общий объем выделенной памяти для JVM Windows должен быть больше, чем тот, который JVM делает доступным для вашей программы в виде динамической памяти.

0 голосов
/ 08 марта 2011

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

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