Максимальный размер кучи Java для 32-разрядной JVM в 64-разрядной ОС
Вопрос не в максимальном размере кучи в 32-битной ОС, учитывая, что максимальный размер адресуемой памяти в 32-битных ОС составляет 4 ГБ, а максимальный размер кучи JVM зависит от того, сколько свободной памяти можно зарезервировать.
Меня больше интересует знание максимального (как теоретического, так и практически достижимого) размера кучи для 32-разрядной JVM, работающей в 64-разрядной ОС. В основном, я смотрю на ответы, похожие на цифры в связанном вопросе о SO.
Что касается того, почему вместо 64-битной используется 32-битная JVM, причина не в технической, а в административной / бюрократической - вероятно, уже слишком поздно устанавливать 64-битную JVM в производственную среду.
16 ответов
32-разрядные JVM, которые ожидают иметь один большой кусок памяти и используют необработанные указатели, не могут использовать более 4 ГБ (поскольку это 32-разрядное ограничение, которое также применяется к указателям). Это включает в себя Sun и, я уверен, также реализации IBM. Я не знаю, если, например, у JRockit или других есть большой выбор памяти с их 32-битными реализациями.
Если вы ожидаете, что достигнете этого предела, вам настоятельно рекомендуется запустить параллельную дорожку для проверки 64-битной JVM для вашей производственной среды, чтобы вы были готовы к тому, когда 32-битная среда выйдет из строя. В противном случае вам придется выполнять эту работу под давлением, что никогда не бывает приятно.
Изменить 2014-05-15: FAQ по Oracle:
Максимальный теоретический предел кучи для 32-разрядной JVM составляет 4 G. Из-за различных дополнительных ограничений, таких как доступный обмен, использование адресного пространства ядра, фрагментация памяти и издержки на виртуальные машины, на практике этот предел может быть намного ниже. В большинстве современных 32-разрядных систем Windows максимальный размер кучи будет варьироваться от 1,4 ГГ до 1,6 ГБ. В 32-битных ядрах Solaris адресное пространство ограничено 2G. В 64-разрядных операционных системах, работающих под управлением 32-разрядной виртуальной машины, максимальный размер кучи может быть выше, приближаясь к 4 G во многих системах Solaris.
( http://www.oracle.com/technetwork/java/hotspotfaq-138619.html)
Вы можете спросить Java Runtime:
public class MaxMemory {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
long totalMem = rt.totalMemory();
long maxMem = rt.maxMemory();
long freeMem = rt.freeMemory();
double megs = 1048576.0;
System.out.println ("Total Memory: " + totalMem + " (" + (totalMem/megs) + " MiB)");
System.out.println ("Max Memory: " + maxMem + " (" + (maxMem/megs) + " MiB)");
System.out.println ("Free Memory: " + freeMem + " (" + (freeMem/megs) + " MiB)");
}
}
Это сообщит о "Максимальном объеме памяти" на основе распределения кучи по умолчанию. Так что вам все равно придется играть с -Xmx
(на HotSpot). Я обнаружил, что при работе в 64-разрядной версии Windows 7 Enterprise моя 32-разрядная JVM HotSpot может выделять до 1577 МБ:
[C: нуля]> Java -Xmx1600M MaxMemory Произошла ошибка при инициализации ВМ Не удалось зарезервировать достаточно места для кучи объектов Не удалось создать виртуальную машину Java. [C: нуля]> Java -Xmx1590M MaxMemory Общая память: 2031616 (1,9375 МиБ) Макс. Память: 1654456320 (1577,8125 МБ) Свободная память: 1840872 (1,75559234619 МБ) [C: царапина]>
Принимая во внимание, что с 64-разрядной JVM в той же ОС, конечно, это намного выше (около 3 ТБ)
[C: нуля]> Java -Xmx3560G MaxMemory Произошла ошибка при инициализации ВМ Не удалось зарезервировать достаточно места для кучи объектов [C: нуля]> Java -Xmx3550G MaxMemory Общая память: 94240768 (89,875 МиБ) Макс. Память: 3388252028928 (3184151,84297 МБ) Свободная память: 93747752 (89,4048233032 МБ) [C: царапина]>
Как уже упоминали другие, это зависит от ОС.
- Для 32-битной Windows: это будет <2 ГБ ( внутренняя книга Windows говорит 2 ГБ для пользовательских процессов)
- Для 32-битной BSD / Linux: <3 ГБ (из Книги Дьявола)
- Для 32-разрядных MacOS X: <4 ГБ (из внутренней книги Mac OS X)
- Не уверен насчет 32-битного Solaris, попробуйте приведенный выше код и сообщите нам.
Для 64-битной операционной системы, если JVM является 32-битной, она все равно будет зависеть, скорее всего, как описано выше.
- ОБНОВЛЕНИЕ 20110905: я просто хотел указать на некоторые другие наблюдения / детали:
- Аппаратное обеспечение, на котором я работал, было 64-битным с установленной 6 ГБ ОЗУ. Операционная система была Windows 7 Enterprise, 64-битная
- Фактическая сумма
Runtime.MaxMemory
То, что может быть выделено, также зависит от рабочего набора операционной системы. Однажды я запустил эту программу, когда у меня также был запущен VirtualBox, и обнаружил, что не могу успешно запустить JSM HotSpot с-Xmx1590M
и должен был пойти меньше. Это также означает, что вы можете получить более 1590 МБ в зависимости от размера вашего рабочего набора в то время (хотя я все еще утверждаю, что он будет ниже 2 ГБ для 32-разрядных из-за дизайна Windows)
Вы не указываете, какая ОС.
Под Windows (для моего приложения - долго работающего приложения для управления рисками) мы заметили, что на Windows 32bit мы не можем идти дальше 1280 МБ. Я сомневаюсь, что запуск 32-битной JVM под 64-битной будет иметь какое-либо значение.
Мы портировали приложение на Linux, и мы работаем с 32-битной JVM на 64-битном оборудовании, а виртуальная машина на 2,2 ГБ работала довольно легко.
Самая большая проблема, которую вы можете иметь, - это сборщик мусора, в зависимости от того, для чего вы используете память.
"Для 32-разрядной модели процесса максимальный размер виртуального адреса процесса обычно составляет 4 ГБ, хотя некоторые операционные системы ограничивают его до 2 ГБ или 3 ГБ. Максимальный размер кучи обычно составляет -Xmx3800m (1600m) для ограничений 2 ГБ.), хотя фактическое ограничение зависит от приложения. Для 64-разрядных моделей процессов максимальное ограничение практически не ограничено ".
Нашел довольно хороший ответ здесь: максимальная память Java на Windows XP.
У нас недавно был некоторый опыт с этим. Мы недавно перенесли с Solaris (x86-64 версии 5.10) на Linux (RedHat x86-64) и поняли, что у нас меньше памяти для 32-битного процесса JVM в Linux, чем в Solaris.
Для Solaris это почти до 4 ГБ (http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_heap_32bit).
Мы запустили наше приложение с -Xms2560m -Xmx2560m -XX:MaxPermSize=512m -XX:PermSize=512m без проблем в Solaris в течение последних нескольких лет. Попытка переместить его в Linux, и у нас были проблемы со случайными ошибками нехватки памяти при запуске. Мы могли только заставить его последовательно запускаться на -Xms2300 -Xmx2300. Тогда нам сообщили об этом из поддержки.
32-разрядный процесс в Linux имеет максимальное адресуемое адресное пространство 3 ГБ (3072 МБ), тогда как в Solaris это полный 4 ГБ (4096 МБ).
Ограничения 32-разрядной JVM в 64-разрядной ОС будут точно такими же, как ограничения 32-разрядной JVM в 32-разрядной ОС. В конце концов, 32-разрядная JVM будет работать на 32-разрядной виртуальной машине (в смысле виртуализации), поэтому она не будет знать, что она работает на 64-разрядной ОС / машине.
Одним из преимуществ использования 32-разрядной JVM в 64-разрядной ОС по сравнению с 32-разрядной ОС является то, что у вас может быть больше физической памяти, и, следовательно, вы будете сталкиваться с подкачкой / подкачкой реже. Однако это преимущество полностью реализуется только при наличии нескольких процессов.
Что касается того, почему вместо 64-битной используется 32-битная JVM, причина не в технической, а в административной / бюрократической...
Когда я работал в BEA, мы обнаружили, что в 64-битной JVM среднее приложение работает медленнее, чем в 32-битной JVM. В некоторых случаях снижение производительности было на 25% медленнее. Итак, если вашему приложению действительно не нужна вся эта дополнительная память, вам лучше настроить больше 32-битных серверов.
Насколько я помню, тремя наиболее распространенными техническими обоснованиями для использования 64-разрядных систем, с которыми столкнулись сотрудники службы профессионального обслуживания BEA, были:
- Приложение манипулирует несколькими массивными изображениями,
- Приложение делало массовые вычисления,
- У приложения была утечка памяти, заказчик был главным в государственном контракте, и они не хотели тратить время и средства на отслеживание утечки памяти. (Использование огромной кучи памяти увеличит MTBF, а простое число все равно будет оплачено)
,
Вот некоторые тесты под Solaris и Linux 64-bit
Машина Solaris 10 - SPARC - T5220 с 32 ГБ оперативной памяти (и около 9 ГБ свободной)
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3750m MaxMemory
Error occurred during initialization of VM
Could not reserve space for ObjectStartArray
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3700m MaxMemory
Total Memory: 518520832 (494.5 MiB)
Max Memory: 3451912192 (3292.0 MiB)
Free Memory: 515815488 (491.91998291015625 MiB)
Current PID is: 28274
Waiting for user to press Enter to finish ...
$ java -version
java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) Server VM (build 20.5-b03, mixed mode)
$ which java
/usr/bin/java
$ file /usr/bin/java
/usr/bin/java: ELF 32-bit MSB executable SPARC Version 1, dynamically linked, not stripped, no debugging information available
$ prstat -p 28274
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
28274 user1 670M 32M sleep 59 0 0:00:00 0.0% java/35
Кстати: очевидно, Java не выделяет много фактической памяти при запуске. Казалось, что занято только около 100 МБ на экземпляр (я начал 10)
Solaris 10 - x86 - VMWare VM с 8 ГБ ОЗУ (около 3 ГБ бесплатно *)
3 ГБ свободной оперативной памяти не совсем так. Существует большой кусок оперативной памяти, который используют кеши ZFS, но у меня нет доступа с правами суперпользователя, чтобы проверить, насколько точно
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3650m MaxMemory
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3600m MaxMemory
Total Memory: 516423680 (492.5 MiB)
Max Memory: 3355443200 (3200.0 MiB)
Free Memory: 513718336 (489.91998291015625 MiB)
Current PID is: 26841
Waiting for user to press Enter to finish ...
$ java -version
java version "1.6.0_41"
Java(TM) SE Runtime Environment (build 1.6.0_41-b02)
Java HotSpot(TM) Server VM (build 20.14-b01, mixed mode)
$ which java
/usr/bin/java
$ file /usr/bin/java
/usr/bin/java: ELF 32-bit LSB executable 80386 Version 1 [FPU], dynamically linked, not stripped, no debugging information available
$ prstat -p 26841
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
26841 user1 665M 22M sleep 59 0 0:00:00 0.0% java/12
RedHat 5.5 - x86 - VMWare VM с 4 ГБ ОЗУ (используется около 3,8 ГБ - 200 МБ в буферах и 3,1 ГБ в кэшах, поэтому около 3 ГБ свободно)
$ alias java='$HOME/jre/jre1.6.0_34/bin/java'
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3500m MaxMemory
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3450m MaxMemory
Total Memory: 514523136 (490.6875 MiB)
Max Memory: 3215654912 (3066.6875 MiB)
Free Memory: 511838768 (488.1274871826172 MiB)
Current PID is: 21879
Waiting for user to press Enter to finish ...
$ java -version
java version "1.6.0_34"
Java(TM) SE Runtime Environment (build 1.6.0_34-b04)
Java HotSpot(TM) Server VM (build 20.9-b04, mixed mode)
$ file $HOME/jre/jre1.6.0_34/bin/java
/home/user1/jre/jre1.6.0_34/bin/java: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), for GNU/Linux 2.2.5, not stripped
$ cat /proc/21879/status | grep ^Vm
VmPeak: 3882796 kB
VmSize: 3882796 kB
VmLck: 0 kB
VmHWM: 12520 kB
VmRSS: 12520 kB
VmData: 3867424 kB
VmStk: 88 kB
VmExe: 40 kB
VmLib: 14804 kB
VmPTE: 96 kB
Та же машина с использованием JRE 7
$ alias java='$HOME/jre/jre1.7.0_21/bin/java'
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3500m MaxMemory
Error occurred during initialization of VM
Could not reserve enough space for object heap
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
$ java -XX:PermSize=128M -XX:MaxPermSize=256M -Xms512m -Xmx3450m MaxMemory
Total Memory: 514523136 (490.6875 MiB)
Max Memory: 3215654912 (3066.6875 MiB)
Free Memory: 511838672 (488.1273956298828 MiB)
Current PID is: 23026
Waiting for user to press Enter to finish ...
$ java -version
java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) Server VM (build 23.21-b01, mixed mode)
$ file $HOME/jre/jre1.7.0_21/bin/java
/home/user1/jre/jre1.7.0_21/bin/java: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
$ cat /proc/23026/status | grep ^Vm
VmPeak: 4040288 kB
VmSize: 4040288 kB
VmLck: 0 kB
VmHWM: 13468 kB
VmRSS: 13468 kB
VmData: 4024800 kB
VmStk: 88 kB
VmExe: 4 kB
VmLib: 10044 kB
VmPTE: 112 kB
JVM JROCKIT, в настоящее время принадлежащая Oracle, поддерживает несмежное использование кучи, что позволяет 32-битной JVM получить доступ к более чем 3,8 ГБ памяти, когда JVM работает в 64-битной ОС Windows. (2,8 ГБ при работе на 32-битной ОС).
http://blogs.oracle.com/jrockit/entry/how_to_get_almost_3_gb_heap_on_windows
JVM можно бесплатно загрузить (требуется регистрация) по адресу
http://www.oracle.com/technetwork/middleware/jrockit/downloads/index.html
Должно быть намного лучше
Для 32-битной JVM, работающей на 64-битном хосте, я представляю, что останется куча, это будет любое нефрагментированное виртуальное пространство, доступное после JVM, его собственных DLL и любых загруженных 32-битных компонентов совместимости с ОС. Как дикое предположение, я бы подумал, что 3ГБ должно быть возможным, но насколько это лучше, зависит от того, насколько хорошо вы справляетесь с 32-битной хост-страной.
Кроме того, даже если вы могли бы создать гигантскую кучу в 3 ГБ, вы, возможно, этого не захотите, поскольку это может привести к тому, что паузы в GC станут потенциально неприятными. Некоторые люди просто запускают больше JVM, чтобы использовать дополнительную память, а не одну гигантскую. Я предполагаю, что они настраивают JVM прямо сейчас, чтобы лучше работать с гигантскими кучами.
Трудно точно понять, насколько лучше ты можешь сделать. Я думаю, что ваша 32-битная ситуация может быть легко определена экспериментом. Безусловно, это трудно предсказать абстрактно, так как на это влияют многие факторы, особенно потому, что виртуальное пространство, доступное на 32-разрядных хостах, довольно ограничено. Куча должна существовать в смежной виртуальной памяти, поэтому фрагментация адресного пространства для Использование DLL и внутреннее использование адресного пространства ядром ОС определит диапазон возможных распределений.
ОС будет использовать часть адресного пространства для отображения устройств HW и своих собственных динамических распределений. Хотя эта память не отображается в адресное пространство процесса Java, ядро ОС не может получить к нему доступ и к вашему адресному пространству одновременно, поэтому оно ограничит размер виртуального пространства любой программы.
Загрузка DLL зависит от реализации и выпуска JVM. Загрузка ядра ОС зависит от огромного количества вещей, релиза, HW, от того, сколько оно отображено с момента последней перезагрузки, кто знает...
В итоге
Бьюсь об заклад, вы получаете 1-2 ГБ в 32-битной земле и около 3 в 64-битной, поэтому общее улучшение примерно в 2 раза.
На Solaris ограничение было около 3,5 ГБ, начиная с Solaris 2.5. (около 10 лет назад)
У меня были те же проблемы с JVM, которые использует App Inventor для Android Blocks Editor. Он устанавливает кучу на 925 м макс. Этого недостаточно, но я не мог установить его более чем на 1200 м, в зависимости от различных случайных факторов на моей машине.
Я скачал Nightly, бета-64-битный браузер от Firefox, а также 64-битную версию JAVA 7.
Я еще не нашел свой новый предел кучи, но я только что открыл JVM с размером кучи 5900м. Нет проблем!
Я использую Win 7 64 bit Ultimate на машине с 24 ГБ ОЗУ.
Ограничение также связано с тем, что для 32 bit
ВМ, heap
сам должен начинаться с нулевого адреса, если вы хотите, чтобы все эти 4GB
.
Подумайте об этом, если вы хотите ссылаться на что-то через:
0000....0001
то есть: ссылка, которая имеет это конкретное представление битов, это означает, что вы пытаетесь получить доступ к самой первой памяти из кучи. Чтобы это было возможно, куча должна начинаться с нулевого адреса. Но этого никогда не происходит, он начинается с некоторого смещения от нуля:
| .... .... {heap_start .... heap_end} ... |
--> (this can't be referenced) <--
Поскольку куча никогда не начинается с нулевого адреса в OS
, есть немало бит, которые никогда не используются из 32
ссылка на биты, и поэтому куча, на которую можно ссылаться, ниже.
Я пытался установить размер кучи до 2200M на 32-битной машине Linux, и JVM работала нормально. JVM не запускалась, когда я установил его на 2300M.
Еще один момент для горячей точки 32-битной JVM:- собственная емкость кучи = 4 гигабайта - куча Java - PermGen;
Это может быть особенно сложно для 32-битной JVM, так как Java Heap и native Heap находятся в гонке. Чем больше ваша куча Java, тем меньше собственная куча. Попытка настроить большую кучу для 32-битной виртуальной машины, например, 2,5 ГБ +, увеличивает риск появления собственной ошибки OutOfMemoryError в зависимости от занимаемой площади приложения (ов), количества потоков и т. Д.
Это тяжелая настройка, но вы можете получить кучу 3 ГБ.
Теоретически 4Гб, но на практике (для IBM JVM):
Win 2k8 64, IBM Websphere Application Server 8.5.5 32bit
C:\IBM\WebSphere\AppServer\bin>managesdk.bat -listAvailable -verbose CWSDK1003I: Доступные SDK: CWSDK1005I: Имя SDK: 1.6_32 - com.ibm.websphere.sdk.version.1.6_32=1.6 - com.ibm.websphere.sdk.bits.1.6_32=32 - com.ibm.websphere.sdk.location.1.6_32=${WAS_INSTALL_ROOT}/java - com.ibm.websphere.sdk.platform.1.6_32=windows - com.ibm.websphere.sdk.architecture.1.6_32=x86_32 - com.ibm.websphere.sdk.nativeLibPath.1.6_32=${WAS_INSTALL_ROOT}/lib/native/win /x86_32/
CWSDK1001I: Задача managesdk выполнена успешно.
C:\IBM\WebSphere\AppServer\java\bin>java -Xmx2036 MaxMemory
JVMJ9GC017E -Xmx слишком мала, должна быть не меньше 1 M байт
JVMJ9VM015W Ошибка инициализации для библиотеки j9gc26(2): Не удалось инициализи
ровать
Could not create the Java virtual machine.
C:\IBM\WebSphere\AppServer\java\bin>java -Xmx2047M MaxMemory
Total Memory: 4194304 (4.0 MiB)
Max Memory: 2146435072 (2047.0 MiB)
Free Memory: 3064536 (2.9225692749023438 MiB)
C:\IBM\WebSphere\AppServer\java\bin>java -Xmx2048M MaxMemory
JVMJ9VM015W Ошибка инициализации для библиотеки j9gc26(2): Не удалось создать эк
земпляр кучи; запрошено 2G
Could not create the Java virtual machine.
RHEL 6.4 64, IBM Websphere Application Server 8.5.5 32bit
[bin]./java -Xmx3791M MaxMemory
Total Memory: 4194304 (4.0 MiB)
Max Memory: 3975151616 (3791.0 MiB)
Free Memory: 3232992 (3.083221435546875 MiB)
[root@nagios1p bin]# ./java -Xmx3793M MaxMemory
Total Memory: 4194304 (4.0 MiB)
Max Memory: 3977248768 (3793.0 MiB)
Free Memory: 3232992 (3.083221435546875 MiB)
[bin]# /opt/IBM/WebSphere/AppServer/bin/managesdk.sh -listAvailable -verbose
CWSDK1003I: Available SDKs :
CWSDK1005I: SDK name: 1.6_32
- com.ibm.websphere.sdk.version.1.6_32=1.6
- com.ibm.websphere.sdk.bits.1.6_32=32
- com.ibm.websphere.sdk.location.1.6_32=${WAS_INSTALL_ROOT}/java
- com.ibm.websphere.sdk.platform.1.6_32=linux
- com.ibm.websphere.sdk.architecture.1.6_32=x86_32
-com.ibm.websphere.sdk.nativeLibPath.1.6_32=${WAS_INSTALL_ROOT}/lib/native/linux/x86_32/
CWSDK1001I: Successfully performed the requested managesdk task.