works how example collector java memory garbage-collection jvm heap-memory

java - how - ¿Por qué-Xmx y Runtime.maxMemory no están de acuerdo?



java garbage collector how it works (1)

La diferencia parece deberse al tamaño del espacio de sobrevivientes del recolector de basura.

El indicador -Xmx , como se describe en los docs , controla el tamaño máximo del grupo de asignación de memoria. La parte de almacenamiento dinámico del grupo de asignación de memoria se divide en espacios de Edén, Sobreviviente y Tenencia. Como se describe en esta respuesta , hay dos regiones de sobrevivientes, solo una de las cuales está disponible para mantener objetos vivos en un momento dado. Por lo tanto, el espacio aparente total disponible para asignar objetos, según lo informado por Runtime.maxMemory() , debe restar el tamaño de uno de los espacios de sobrevivientes de la agrupación total de memoria del montón.

Puede usar las clases MemoryMXBean y MemoryPoolMXBean para obtener un poco más de información sobre su asignación de memoria. Aquí hay un programa simple que escribí:

import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryPoolMXBean; public class MemTest { static String mb (long s) { return String.format("%d (%.2f M)", s, (double)s / (1024 * 1024)); } public static void main(String[] args) { System.out.println("Runtime max: " + mb(Runtime.getRuntime().maxMemory())); MemoryMXBean m = ManagementFactory.getMemoryMXBean(); System.out.println("Non-heap: " + mb(m.getNonHeapMemoryUsage().getMax())); System.out.println("Heap: " + mb(m.getHeapMemoryUsage().getMax())); for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) { System.out.println("Pool: " + mp.getName() + " (type " + mp.getType() + ")" + " = " + mb(mp.getUsage().getMax())); } } }

La salida de esto en OpenJDK 7 para java -Xmx1024m MemTest es:

Runtime max: 1037959168 (989.88 M) Non-heap: 224395264 (214.00 M) Heap: 1037959168 (989.88 M) Pool: Code Cache (type Non-heap memory) = 50331648 (48.00 M) Pool: Eden Space (type Heap memory) = 286326784 (273.06 M) Pool: Survivor Space (type Heap memory) = 35782656 (34.13 M) Pool: Tenured Gen (type Heap memory) = 715849728 (682.69 M) Pool: Perm Gen (type Non-heap memory) = 174063616 (166.00 M)

Tenga en cuenta que Eden + 2 * Survivor + Tenured = 1024M, que es exactamente la cantidad de espacio de almacenamiento requerido en la línea de comandos. Muchas gracias a @ Absurd-Mind por señalar esto.

Las diferencias que usted observa entre diferentes JVM probablemente se deben a heurísticas diferentes para seleccionar los tamaños relativos predeterminados de las distintas generaciones. Como se describe en este artículo (se aplica a Java 6, no se pudo encontrar una más reciente), puede usar las -XX:NewRatio y -XX:SurvivorRatio para controlar explícitamente estas configuraciones. Entonces, ejecutando el comando:

java -Xmx1024m -XX:NewRatio=3 -XX:SurvivorRatio=6

Le estás diciendo a la JVM que:

Young:Tenured = (Eden + 2*Survivor):Tenured = 1:3 = 256m:768m Survivor:Eden = 1:6 = 32m:192m

Entonces, con estos parámetros, la diferencia entre el valor solicitado de -Xmx y la memoria disponible reportada por Runtime.maxMemory() debe ser de 32 m, que se verifica mediante el programa anterior. Y ahora debería poder predecir con precisión la memoria disponible reportada por Runtime para un conjunto dado de argumentos de línea de comando, que es todo lo que realmente deseaba, ¿verdad?

Cuando agregues

-Xmx????m

En la línea de comandos, la JVM le proporciona un montón que está cerca de este valor, pero puede salir hasta en un 14%. La JVM puede darle una cifra mucho más cercana a lo que desea, pero solo a través de prueba y error.

System.out.println(Runtime.getRuntime().maxMemory());

huellas dactilares

-Xmx1000m -> 932184064 -Xmx1024m -Xmx1g -> 954728448 -Xmx1072m -> 999292928 -Xmx1073m -> 1001390080

Estoy ejecutando HotSpot Java 8 actualización 5.

Claramente, el montón puede ser algo por encima de 1000000000 pero ¿por qué es esto -Xmx1073m lugar de decir -Xmx1000m ?

BTW 1g == 1024m que sugiere que 1g debería ser 1024 ^ 3, que es un 7% más alto que 1000 ^ 3, pero obtienes algo un 7% más bajo que 1000 ^ 3.

Estar fuera por tanto sugiere que me estoy perdiendo algo fundamental acerca de cómo funciona el montón. Si pidiera -Xmx1000m y fuera 1001390080 no me importaría, supondría que hay una asignación múltiple que debe cumplir, pero para darle 932184064 me sugiere que el montón es más complicado de lo que puedo imaginar.

EDITAR, he encontrado que

-Xmx1152m gives 1073741824 which is exactly 1024^3

por lo que parece que me está dando exactamente 128 MB menos de lo que pedí en este caso, consulte el maxMemory ().

BTW 128 es mi número favorito. Hoy estuve en una conferencia en la calle número 128 y el orador citó un libro de la página 128 ;)