Tamaño máximo de almacenamiento dynamic de Java de una JVM de 32 bits en un sistema operativo de 64 bits

La pregunta no es sobre el tamaño de almacenamiento dynamic máximo en un sistema operativo de 32 bits, dado que los sistemas operativos de 32 bits tienen un tamaño máximo de memoria direccionable de 4 GB y que el tamaño de almacenamiento dynamic máximo de la JVM depende de la cantidad de memoria libre contigua que pueda reservarse.

Estoy más interesado en conocer el tamaño de montón máximo (tanto teórico como prácticamente alcanzable) para una JVM de 32 bits que se ejecuta en un sistema operativo de 64 bits. Básicamente, estoy buscando respuestas similares a las cifras en una pregunta relacionada sobre SO .

En cuanto a por qué se utiliza una JVM de 32 bits en lugar de una de 64 bits, la razón no es técnica, sino administrativa / burocrática: probablemente sea demasiado tarde para instalar una JVM de 64 bits en el entorno de producción.

Las JVM de 32 bits que esperan tener una gran porción de memoria y usar punteros sin formato no pueden usar más de 4 Gb (ya que ese es el límite de 32 bits que también se aplica a los punteros). Esto incluye a Sun y, estoy bastante seguro, también las implementaciones de IBM. No sé si, por ejemplo, JRockit u otros tienen una gran opción de memoria con sus implementaciones de 32 bits.

Si espera alcanzar este límite, debería considerar comenzar una ruta paralela que valide una JVM de 64 bits para su entorno de producción, de modo que esté listo para cuando se rompa el entorno de 32 bits. De lo contrario, tendrás que hacer ese trabajo bajo presión, lo cual nunca es agradable.


Editar 2014-05-15: Preguntas frecuentes de Oracle:

El límite máximo de montón teórico para la JVM de 32 bits es 4G. Debido a varias restricciones adicionales, como el intercambio disponible, el uso del espacio de direcciones del núcleo, la fragmentación de la memoria y la sobrecarga de VM, en la práctica el límite puede ser mucho menor. En la mayoría de los sistemas modernos de Windows de 32 bits, el tamaño máximo del almacenamiento dynamic variará de 1.4G a 1.6G. En kernels de Solaris de 32 bits, el espacio de direcciones está limitado a 2G. En los sistemas operativos de 64 bits que ejecutan la VM de 32 bits, el tamaño máximo de almacenamiento dynamic puede ser mayor, acercándose a 4G en muchos sistemas Solaris.

( http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_heap_32bit )

Puede consultar 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)"); } } 

Esto informará la “memoria máxima” en función de la asignación de stack predeterminada. Por lo tanto, aún necesitaría jugar con -Xmx (en HotSpot ). Descubrí que al ejecutar Windows 7 Enterprise de 64 bits, mi HotSpot JVM de 32 bits puede asignar hasta 1577Mib:

 [C: scratch]> java -Xmx1600M MaxMemory
 Se produjo un error durante la inicialización de la VM
 No se pudo reservar suficiente espacio para el montón de objetos
 No se pudo crear la máquina virtual de Java.
 [C: scratch]> java -Xmx1590M MaxMemory
 Memoria total: 2031616 (1.9375 MiB)
 Memoria máxima: 1654456320 (1577.8125 MiB)
 Memoria libre: 1840872 (1.75559234619 MiB)
 [C: scratch]>

Mientras que con una JVM de 64 bits en el mismo sistema operativo, por supuesto, es mucho más alta (alrededor de 3TiB)

 [C: scratch]> java -Xmx3560G MaxMemory
 Se produjo un error durante la inicialización de la VM
 No se pudo reservar suficiente espacio para el montón de objetos
 [C: scratch]> java -Xmx3550G MaxMemory
 Memoria total: 94240768 (89.875 MiB)
 Memoria máxima: 3388252028928 (3184151.84297 MiB)
 Memoria libre: 93747752 (89.4048233032 MiB)
 [C: scratch]>

Como otros ya han mencionado, depende del sistema operativo.

  • Para Windows de 32 bits: será <2 GB ( el libro interno de Windows dice 2 GB para los procesos de usuario)
  • Para BSD / Linux de 32 bits: <3 GB (del Libro del Diablo)
  • Para MacOS X de 32 bits: <4 GB (del libro interno de Mac OS X )
  • No estoy seguro acerca de Solaris de 32 bits, pruebe el código anterior y avísenos.

Para un sistema operativo host de 64 bits, si la JVM es de 32 bits, todavía dependerá, muy probablemente como se demostró anteriormente.

– ACTUALIZACIÓN 20110905 : Solo quería señalar algunas otras observaciones / detalles:

  • El hardware con el que ejecuté esto fue de 64 bits con 6 GB de RAM real instalada. El sistema operativo era Windows 7 Enterprise, de 64 bits
  • La cantidad real de Runtime.MaxMemory que se puede asignar también depende del conjunto de trabajo del sistema operativo. Una vez ejecuté esto mientras también ejecutaba VirtualBox y descubrí que no podía iniciar con éxito la HotSpot JVM con -Xmx1590M y tenía que -Xmx1590M tamaño. Esto también implica que puede obtener más de 1590M dependiendo del tamaño de su conjunto de trabajo en ese momento (aunque sigo manteniendo que será inferior a 2GiB para 32 bits debido al diseño de Windows)

Usted no especifica qué sistema operativo.

En Windows (para mi aplicación, una aplicación de administración de riesgos de larga ejecución) observamos que no podíamos ir más allá de 1280 MB en Windows 32 bits. Dudo que ejecutar una JVM de 32 bits en 64 bits haga una diferencia.

Transmitimos la aplicación a Linux y estamos ejecutando una JVM de 32 bits en hardware de 64 bits y hemos tenido una VM de 2.2 GB ejecutándose con bastante facilidad.

El problema más grande que puede tener es GC, dependiendo de para qué está usando la memoria.

Desde 4.1.2 Tamaño de Heap :

“Para un modelo de proceso de 32 bits, el tamaño máximo de la dirección virtual del proceso suele ser de 4 GB, aunque algunos sistemas operativos lo limitan a 2 GB o 3 GB. El tamaño máximo de almacenamiento dynamic es típicamente -Xmx3800m (1600m) para límites de 2 GB ), aunque la limitación real depende de la aplicación. Para los modelos de proceso de 64 bits, el máximo es esencialmente ilimitado “.

Encontré una muy buena respuesta aquí: memoria máxima de Java en Windows XP .

Recientemente tuvimos algo de experiencia con esto. Hemos migrado de Solaris (x86-64 versión 5.10) a Linux (RedHat x86-64) recientemente y nos hemos dado cuenta de que tenemos menos memoria disponible para un proceso JVM de 32 bits en Linux que Solaris.

Para Solaris esto casi llega a 4 GB (http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_heap_32bit).

Ejecutamos nuestra aplicación con -Xms2560m -Xmx2560m -XX: MaxPermSize = 512m -XX: PermSize = 512m sin problemas en Solaris en los últimos años. Intenté moverlo a Linux y tuvimos problemas con los errores aleatorios de falta de memoria en el inicio. Solo pudimos hacer que comenzara de manera constante en -Xms2300 -Xmx2300 . Entonces fuimos advertidos de esto por apoyo.

Un proceso de 32 bits en Linux tiene un espacio de direcciones direccionable máximo de 3gb (3072mb) mientras que en Solaris es el máximo de 4gb (4096mb).

Las limitaciones de una JVM de 32 bits en un sistema operativo de 64 bits serán exactamente las mismas que las limitaciones de una JVM de 32 bits en un sistema operativo de 32 bits. Después de todo, la JVM de 32 bits se ejecutará en una máquina virtual de 32 bits (en el sentido de virtualización) por lo que no sabrá que se está ejecutando en una máquina / sistema operativo de 64 bits.

La única ventaja de ejecutar una JVM de 32 bits en un sistema operativo de 64 bits en comparación con un sistema operativo de 32 bits es que puede tener más memoria física y, por lo tanto, encontrará intercambio / paginación con menos frecuencia. Sin embargo, esta ventaja solo se realiza plenamente cuando tiene múltiples procesos.

En cuanto a por qué se usa una JVM de 32 bits en lugar de una de 64 bits, la razón no es técnica sino administrativa / burocrática …

Cuando trabajaba para BEA, descubrimos que la aplicación promedio realmente funcionaba más despacio en una JVM de 64 bits, luego lo hacía cuando se ejecutaba en una JVM de 32 bits. En algunos casos, el golpe de rendimiento fue tan alto como un 25% más lento. Entonces, a menos que su aplicación realmente necesite toda esa memoria adicional, sería mejor configurar más servidores de 32 bits.

Según recuerdo, las tres justificaciones técnicas más comunes para usar un 64 bits que el personal de servicios profesionales de BEA encontró fueron:

  1. La aplicación estaba manipulando múltiples imágenes masivas,
  2. La aplicación estaba haciendo una gran cantidad de números,
  3. La aplicación tenía una fuga de memoria, el cliente era el principal en un contrato con el gobierno, y no querían tomarse el tiempo y el gasto de rastrear la fuga de memoria. (Usar un montón de memoria masiva boostía el MTBF y aún se pagaría el principal)

.

JROCKIT JVM, actualmente propiedad de Oracle, admite el uso de stacks no contiguas, lo que permite que la JVM de 32 bits acceda a más de 3,8 GB de memoria cuando la JVM se ejecuta en un sistema operativo Windows de 64 bits. (2,8 GB cuando se ejecuta en un sistema operativo de 32 bits).

http://blogs.oracle.com/jrockit/entry/how_to_get_almost_3_gb_heap_on_windows

La JVM puede descargarse libremente (se requiere registro) en

http://www.oracle.com/technetwork/middleware/jrockit/downloads/index.html

Aquí hay algunas pruebas bajo Solaris y Linux de 64 bits

Solaris 10 – SPARC – T5220 máquina con 32 GB de RAM (y alrededor de 9 GB gratis)

 $ 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 

Por cierto: aparentemente, Java no asigna mucha memoria real con el inicio. Parecía que solo se necesitaban unos 100 MB por instancia (comencé 10)

Solaris 10 – x86 – VMWare VM con 8 GB de RAM (alrededor de 3 GB gratis *)

Los 3 GB de RAM libre no son realmente ciertos. Hay una gran cantidad de RAM que usan los cachés de ZFS, pero no tengo acceso de root para verificar cuánto exactamente

 $ 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 – Máquina virtual VMWare con 4 GB de RAM (se utilizan alrededor de 3,8 GB, 200 MB en almacenamientos intermedios y 3,1 GB en cachés, por lo que unos 3 GB son gratuitos)

 $ 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 

Misma máquina usando 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 

Debería ser mucho mejor

Para una JVM de 32 bits que se ejecuta en un host de 64 bits, imagino que lo que sobra para el montón será el espacio virtual no fragmentado disponible después de la JVM, sus propias DLL y cualquier cosa de compatibilidad con OS de 32 bits. Como supongo, creo que 3GB debería ser posible, pero cuánto mejor depende de qué tan bien estés en 32-bit-host-land.

Además, incluso si pudieras hacer un montón gigante de 3GB, es posible que no quieras, ya que esto provocará que las pausas de GC se vuelvan potencialmente problemáticas. Algunas personas simplemente ejecutan más JVM para usar la memoria extra en lugar de una gigante. Me imagino que están sintonizando las JVM ahora para trabajar mejor con montones gigantes.

Es un poco difícil saber exactamente cuánto mejor puede hacer. Supongo que su situación de 32 bits se puede determinar fácilmente mediante el experimento. Ciertamente es difícil de predecir de manera abstracta, ya que muchas cosas tienen un factor, especialmente porque el espacio virtual disponible en los hosts de 32 bits es bastante limitado. El montón no necesita existir en la memoria virtual contigua, por lo que la fragmentación del espacio de direcciones para dll y el uso interno del espacio de direcciones por el núcleo del sistema operativo determinará el rango de posibles asignaciones.

El SO utilizará parte del espacio de direcciones para mapear dispositivos HW y sus propias asignaciones dinámicas. Si bien esta memoria no está asignada al espacio de direcciones del proceso de Java, el kernel del sistema operativo no puede acceder a ella y a su espacio de direcciones al mismo tiempo, por lo que limitará el tamaño del espacio virtual de cualquier progtwig.

La carga de DLL depende de la implementación y el lanzamiento de la JVM. Cargar el núcleo del sistema operativo depende de una gran cantidad de cosas, la versión, el hardware, cuántas cosas ha mapeado hasta ahora desde el último reinicio, quién sabe …

En resumen

Apuesto a que obtienes 1-2 GB en 32-bit-land, y aproximadamente 3 en 64-bit, por lo que una mejora general de aproximadamente 2x .

En Solaris, el límite ha sido de 3,5 GB desde Solaris 2.5. (hace unos 10 años)

Estaba teniendo los mismos problemas con la JVM que usa App Inventor for Android Blocks Editor. Establece el montón en 925m máx. Esto no es suficiente, pero no pude establecerlo a más de 1200 m, dependiendo de varios factores aleatorios en mi máquina.

Descargué Nightly, el navegador beta de 64 bits de Firefox, y también la versión JAVA 7 de 64 bits.

Todavía no he encontrado mi nuevo límite de almacenamiento dynamic, pero acabo de abrir una JVM con un tamaño de almacenamiento dynamic de 5900m . ¡No hay problema!

Estoy ejecutando Win 7 64 bit Ultimate en una máquina con 24 gb de RAM.

Intenté establecer el tamaño del almacenamiento dynamic hasta 2200M en una máquina Linux de 32 bits y JVM funcionó bien. La JVM no se inició cuando lo configuré en 2300M.

un punto más aquí para el punto de acceso JVM de 32 bits: – la capacidad del montón nativo = 4 Gig – Java Heap – PermGen;

Puede ser especialmente complicado para JVM de 32 bits, ya que Java Heap y Heap nativo están en una carrera. Cuanto mayor sea tu Heap de Java, menor será el Heap nativo. Intentar configurar un Heap grande para una VM de 32 bits, por ejemplo, .2.5 GB + aumenta el riesgo de OutOfMemoryError nativo dependiendo de la huella de su (s) aplicación (es), el número de Threads, etc.

4gb teóricos, pero en la práctica (para 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.