Простой ответ: -Xmx
не является жестким ограничением для JVM. Он ограничивает доступную кучу до Java внутри JVM. Уменьшите свой -Xmx
, и вы можете стабилизировать память процесса до размера, который вам подходит.
Длинный ответ: JVM - сложная машина. Думайте об этом как об ОС для вашего кода Java. Виртуальной машине действительно требуется дополнительная память для собственного обслуживания (например, метаданные G C), память, занятая размером стека потоков, память вне кучи (например, память, выделенная собственным кодом через JNI; буферы) и т. Д. c .
-Xmx
ограничивает только размер кучи для объектов: память, которая обрабатывается непосредственно в вашем Java коде. Все остальное не учитывается этим параметром.
Есть новый параметр JVM -XX:MaxRam
( 1 , 2 ), который пытается держите всю память процесса в пределах этого лимита.
Из вашего другого вопроса:
Это многопоточность. 100 читателей, 100 писателей. Каждый из них имеет собственное подключение к базе данных.
Имейте в виду, что буферам ввода-вывода ОС также нужна память для их собственных функций.
Если у вас более 200 потоков , вы также платите цену: N*(Stack size)
, и ок. N*(TLAB size)
зарезервировано в Young Gen для каждого потока (динамически изменяемый размер):
java -Xss1024k -XX:+PrintFlagsFinal 2> /dev/null | grep -i tlab
size_t MinTLABSize = 2048
intx ThreadStackSize = 1024
Примерно полгигабайта только для этого (и, возможно, больше)!
Размер стека потоков ( в Кбайтах). (0 означает использовать размер стека по умолчанию) [Spar c: 512; Solaris x86: 320 (было 256 в предыдущих версиях 5.0 и ранее); Spar c 64 бит: 1024; Linux amd64: 1024 (было 0 в 5.0 и ранее); все остальные 0.] - Java Параметры виртуальной машины HotSpot ; Linux x86 JDK source
Вкратце: -Xss
(размер стека) значения по умолчанию зависят от среды виртуальной машины и ОС.
Буферы локального распределения потоков являются более сложными и помогают избежать конфликтов выделения / блокировки ресурсов. Объяснение настройки здесь для их функции: Размещение TLAB и TLAB и анализируемость кучи .
Дополнительная литература: "Native Отслеживание памяти « и Q:« Java с использованием гораздо большего объема памяти, чем размер кучи »
, почему в этом случае выдается ошибка G C, достигнут предел.
«Превышен предел накладных расходов G C» . Вкратце: каждый цикл G C потреблял слишком мало памяти, и решение проблемы эргономики было отменено. Вашему процессу требуется больше памяти.
Когда другой процесс X запускается на том же сервере с другим пользователем, он занимает 14g. Затем один из моих процессов потерпел неудачу.
Еще один момент, связанный с последовательным запуском нескольких процессов с большой памятью, примите во внимание следующее:
java -Xms28g -Xmx28g <...>;
# above process finishes
java -Xms28g -Xmx28g <...>; # crashes, cant allocate enough memory
Когда первый процесс завершится, ваш ОС требуется некоторое время для обнуления памяти, освобожденной конечным процессом, прежде чем она сможет передать эти области физической памяти второму процессу. Для выполнения этой задачи может потребоваться некоторое время, и до тех пор вы не сможете запустить другой «большой» процесс, который немедленно запрашивает полные 28 ГБ кучи (наблюдается в WinNT 6.1). Это можно обойти с помощью:
- Уменьшить
-Xms
, чтобы распределение происходило позже во время жизни 2-го процесса - Уменьшить общее
-Xmx
куча - Отложить запуск второго процесса