Java не резервирует огромный размер начальной кучи

Я работаю над одной машиной с 512 ГБ оперативной памяти (обращаются к нескольким процессорам AMD Opteron 6212). В настоящее время оперативная память составляет около 300 ГБ. Запуск большого вычисления java, запустив

java path/to/myApp -Xms280g -Xmx280g > output.txt

должен немедленно сделать резерв Java 280 ГБ, и ошибка, если это не удастся. Как ни странно, ошибки не возникает, но top показывает только использование памяти в 30,4 ГБ, но это не сбой. Как это может произойти? Разве java не должен сбой, если исходный размер кучи не может быть выделен?

И эффективно, я получаю OutOfMemory/Java heap space/GC overhead limit errors после того, как 30,4 ГБ заполнены, задолго до достижения 280 ГБ. Работа с 250 ГБ или 300 ГБ дает аналогичный предел 30,3 ГБ ~ 30,4 ГБ. Я запускаю 64-разрядную виртуальную машину OpenJDK с помощью среды OpenJDK Runtime Environment (IcedTea6) на Gentoo Linux, и есть много свободной памяти (более 300 ГБ).

Ответы

Ответ 1

Порядок параметров неверен. Вы передаете -Xms280g -Xmx280g в качестве аргументов вашей собственной программы, а не JVM. Правильно:

java -Xms280g -Xmx280g path/to/myApp

Ответ 2

Если вы хотите, чтобы память, указанная в -Xms, была захвачена во время инициализации вашего приложения, используйте

java -XX: + AlwaysPreTouch -Xms2G -Xmx2G......

AlwaysPreTouch будет требовать каждую страницу памяти во время инициализации JVM, а не просто хранить то, что не нужно, как "виртуальное". Однако обратите внимание, что при запуске JVM это будет иметь некоторое задержка.

Используйте вышеупомянутый переключатель, а затем установите флажок в верхней части. Вы получите полный 2G (фактически немного больше) для вашей JVM.

Ответ 3

Попробуйте добавить параметр -d64 в cmdline

java -d64 path/to/myApp -Xms280g -Xmx280g > output.txt

Ответ 4

Таким образом, вы достигаете примерно до 32 ГБ в качестве предела. Хотя Oracle говорит о Compressed oops in the Hotspot JVM, он также говорит о 32 ГБ.

Однако в системе LP64 куча для любого заданного прогона может быть примерно в 1,5 раза больше, чем для соответствующей системы ILP32 (при условии, что запуск подходит для обоих режимов). Это связано с расширенным размером управляемых указателей. Память довольно дешевая, но в наши дни пропускная способность и кеш не хватает, поэтому значительно увеличить размер кучи, чтобы преодолеть ограничение 4Gb, является болезненным.

(Кроме того, на чипах x86 режим ILP32 обеспечивает половину используемых регистров, которые выполняются в режиме LP64. SPARC не влияет на этот путь: чипы RISC начинаются с большого количества регистров и просто расширяют их для режима LP64.)

Сжатые oops представляют управляемые указатели (во многих, но не во всех местах JVM), как 32-битные значения, которые необходимо масштабировать в 8 раз и добавлять к 64-разрядному базовому адресу, чтобы найти объект, на который они ссылаются. Это позволяет приложениям адресовать до четырех миллиардов объектов (не байтов), or a heap size of up to about 32Gb.

Ссылка здесь