64-разрядная JVM ограничена 300 ГБ памяти?

Я пытаюсь запустить приложение Java в среде кластерных вычислений (IBM LSF, работающий с выпуском CentOS версии 6.2 Final), который может предоставить мне до 1 ТБ оперативной памяти.

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

Однако, кажется, невозможно создать JVM с максимальной памятью более 300 ГБ с использованием опции Xmx. Чтобы быть более конкретным, я получаю классическое сообщение об ошибке:

Ошибка при инициализации виртуальной машины.

Не удалось зарезервировать достаточно места для кучи объектов.

Детали моей (64-разрядной) JVM приведены ниже:

Рабочая среда OpenJDK (IcedTea6 1.10.6) (rhel-1.43.1.10.6.el6_2-x86_64)

OpenJDK 64-разрядная серверная VM (сборка 20.0-b11, смешанный режим)

Я также пытался использовать 64-разрядную JVM для Java 7, но у меня была такая же проблема.

Кроме того, я попытался создать JVM для запуска HelloWorld.jar, но создание JVM все же сработает, если вы запрашиваете больше -Xmx300G, поэтому я не думаю, что это имеет какое-либо отношение к конкретному приложению.


Кто-нибудь знает, почему я не могу создать JVM с более чем 300G максимальной памяти?

Может кто-нибудь предложить решение/обход?

Ответ 1

Я могу представить пару возможных объяснений:

  • Другие приложения в вашей системе используют так много памяти, что сейчас доступно не 300Gb.

  • Может существовать ограничение ресурсов на размер памяти для каждого процесса. Вы можете проверить это, используя ulimit. (Обратите внимание, что в соответствии с этой ошибкой вы получите сообщение об ошибке, если ограничение ресурса для каждого процесса остановит JVM, распределяющее области кучи.)

  • Также возможно, что это проблема "over commit"; например если ваше приложение работает в виртуальном режиме, а система в целом не может удовлетворить спрос, потому что конкуренция с другими виртуальными машинами слишком велика.


Несколько других предложенных идей (ИМО) маловероятны:

  • Переключение JRE вряд ли имеет какое-либо значение. Я никогда не слышал или не видел произвольных ограничений памяти в конкретных 64-битных JVM.

  • Маловероятно, что из-за отсутствия достаточной непрерывной памяти. Конечно, непрерывная физическая память не требуется. Единственная возможность может быть смежным пространством на устройстве подкачки, но я не помню, что это проблема для типичных ОС Linux.


Может кто-нибудь предложить решение/обход?

  • Проверьте ulimit.

  • Напишите крошечную программу на C, которая пытается malloc много памяти и посмотреть, сколько из них может выделить до того, как она сработает.

  • Обратитесь за помощью к администратору системы (или гипервизору).

Ответ 2

(отредактирован, см. добавленный раздел об области подкачки)

SHMMAX и SHMALL

Поскольку вы используете CentOS, возможно, вы столкнулись с аналогичной проблемой настройки ядра SHMMAX и SHMALL, как описано здесь для настройки Oracle DB. Под этой же ссылкой приведен пример расчета для получения и установки правильной установки SHMALL.

Непрерывная память

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

Я не уверен, требует ли JVM для CentOS непрерывного блока памяти. Согласно SAS, фрагментированная память может помешать вашей JVM запускаться с максимальным значением max Xmx или начать настройку памяти Xms, но другие требования в Интернете говорят, что это не имеет значения. Я попытался доказать или устранить эту претензию на моей 48-Гбайт рабочей станции Windows, но мне удалось запустить JVM с начальным и максимальным значением 40 ГБ. Я уверен, что не существует непрерывного блока такого размера, но JVM на разных ОС могут вести себя по-разному, потому что управление памятью может отличаться для каждой ОС (то есть Windows обычно скрывает физические адреса для отдельных процессов).

Поиск самого большого смежного блока памяти

Используйте /proc/meminfo, чтобы найти самый большой доступный доступный блок памяти, см. значение под VmAllocChunk. Вот руководство и объяснение всех значений. Если значение, которое вы видите там, меньше 300 ГБ, попробуйте значение, которое падает под значением VmAllocChunk.

Однако обычно это число выше, чем физически доступная память (поскольку это значение виртуальной памяти доступно), это может дать вам ложный результат. Это значение, которое вы можете зарезервировать, но как только вы начнете его использовать, это может потребовать замены. Поэтому вы должны также проверить значения MemFree и Inactive. И наоборот, вы также можете посмотреть весь список и посмотреть, какие значения не превышают 300 ГБ.

Другие параметры настройки, которые вы можете проверить для 64-разрядной JVM

Я не уверен, почему вы, кажется, попали в проблему с ограничениями памяти на 300 ГБ. На мгновение я подумал, что вы можете набрать максимум страниц. По умолчанию 4 КБ, 300 ГБ дает страницы 78,643,200. Не похоже на какое-то известное магическое число. Если, например, 2^24 является максимальным, то 16,777,216 страницы или 64 ГБ должны быть вашим теоретическим распределяемым максимумом.

Однако предположим, что для аргументации вам нужны более крупные страницы (что, как оказалось, лучше для производительности приложений с большой памятью Java), вы должны проконсультируйтесь с этой man-страницей в JBoss, в которой объясняется, как использовать -XX:+UseLargePages и установить kernel.shmmax (там он снова), vm.nr_hugepages и vm.huge_tlb_shm_group (не уверен, что последний требуется).

Настройте систему

Другие предложили это уже сейчас. Чтобы узнать, что проблема связана с JVM, а не с ОС, вы должны сделать это. Один инструмент, который вы можете использовать, - Stresslinux. В этом уроке вы найдете некоторые параметры, которые вы можете использовать. Особый интерес для вас представляет следующая команда:
stress --vm 2 --vm-bytes 300G --timeout 30s --verbose

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

РЕДАКТИРОВАТЬ Apr6: проверить пространство подкачки

Нет ничего необычного в том, что системы с очень большими внутренними объемами памяти используют мало или вообще не занимают места подкачки. Для многих приложений это не проблема, но для JVM требуется, чтобы свободное место подкачки было больше, чем запрошенный размер памяти. Согласно этот отчет об ошибках, JVM попытается сам увеличить пространство подкачки, однако некоторые ответы в этот SO-поток предложил, JVM может не всегда быть в состоянии сделать это.

Следовательно: проверьте доступное в настоящее время пространство подкачки с cat /proc/swaps # free и, если оно меньше 300 ГБ, следуйте инструкции на этой странице руководства CentOS, чтобы увеличить пространство подкачки для вашей системы.

Примечание 1: мы можем вычесть из bugreport # 4719001, что непрерывный блок доступного пространства подкачки не является необходимостью. Но если вы не уверены, удалите все пространство подкачки и заново создайте его, который должен удалить любую фрагментацию.

Примечание 2: я видел несколько сообщений, таких как этот, сообщающий 0MB пространство подкачки и возможность запуска JVM. Вероятно, это связано с тем, что JVM увеличивает пространство подкачки. Все еще не помешает попытаться увеличить пространство подкачки вручную, чтобы выяснить, исправляет ли он вашу проблему.

Преждевременное заключение

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

То, что вы получаете правильную ошибку при инициализации JVM, заставляет меня думать, что проблема не в JVM, а в том, что ОС не может выполнить резервирование 300 ГБ памяти.

Мои собственные тесты показали, что JVM может получить доступ ко всей виртуальной памяти и не заботится о количестве доступной физической памяти. Было бы странно, если бы виртуальная память была ниже физической, но параметр VmAllocChunk должен давать вам подсказку в этом направлении (обычно это намного больше).

Ответ 3

Если вы посмотрите на раздел часто задаваемых вопросов Java HotSpot VM, его упоминалось, что на 64-битных виртуальных машинах есть только 64 адресных бита для работы и поэтому максимальный размер кучи Java зависит от объема физической памяти и пространства подкачки, присутствующих в системе.

Если вы вычислите теоретически, то вы можете иметь память 18446744073709551616 МБ, но для этого есть ограничение.

Вы должны использовать команду -Xmx для определения максимального размера кучи для JVM, По умолчанию, Java использует 64 + 30% = 83,2 МБ на 64-битных JVM.

Я попробовал команду ниже на своей машине, и она выглядела нормально.

java -Xmx500g com.test.TestClass

Я также пытался определить максимальную кучу в терабайтах, но она не работает.

Ответ 4

Запустите ulimit -a как пользователь JVM-процесса и убедитесь, что ваше ядро ​​не ограничивает ваш максимальный размер памяти. Возможно, вам потребуется отредактировать файл/etc/security/limit.conf

Ответ 5

Согласно этой дискуссии, LSF не объединяет память node в одно разделяемое пространство. Вы используете что-то еще для этого. Прочтите эту документацию, потому что возможно, она не может делать то, что вы просите об этом. В частности, возможно, не удастся выделить один непрерывный участок памяти, который охватывает все узлы. Обычно это не нужно, так как приложение будет делать много звонков в malloc. Но JVM, чтобы упростить вещи для себя, хочет выделить (или зарезервировать) единый смежный регион для всей кучи, эффективно вызывая malloc только один раз. Или это может быть что-то еще, связанное с тем, что вы используете для эмуляции гигантской машины общей памяти.