software simulador requisitos plataformas para memoria instalar descargar con compatibles administracion java memory-management

simulador - requisitos de hardware y software para instalar java



Uso excesivo de la memoria de Java 6 (7)

¿Java 6 consume más memoria de la esperada para las aplicaciones más grandes?

Tengo una aplicación que he estado desarrollando durante años, que hasta ahora me ha costado unos 30-40 MB en mi configuración particular de prueba; ahora con Java 6u10 y 11 toma varios cientos mientras está activo. Rebota mucho, entre 50M y 200M, y cuando está inactivo, hace GC y deja caer la memoria hacia abajo. Además, genera millones de fallas de página. Todo esto se observa a través del Administrador de tareas de Windows.

Por lo tanto, lo realicé en mi perfilador (jProfiler) y utilizando jVisualVM, y ambos indican el uso moderado normal de heap y perm-gen de alrededor de 30M combinados, incluso cuando estoy completamente activo haciendo mi ciclo de prueba de carga.

¡Así que estoy desconcertado! Y no solo solicita más memoria del grupo de memoria virtual de Windows, esto aparece como 200M "Uso de memoria".

ACLARACIÓN: Quiero ser perfectamente claro en esto: observado durante un período de 18 horas con Java VisualVM, el montón de clases y el montón de perm gen han sido perfectamente estables. El montón volátil asignado (eden y tenured) se queda inmóvil en 16MB (que alcanza en los primeros minutos), y el uso de esta memoria fluctúa en un patrón perfecto de crecimiento uniformemente de 8MB a 16MB, momento en el que GC patea una lo vuelve a bajar a 8MB. Durante este período de 18 horas, el sistema estuvo bajo carga máxima constante desde que estaba realizando una prueba de esfuerzo. Este comportamiento es reproducible de manera perfecta y consistente , visto en numerosas ejecuciones. La única anomalía es que mientras esto sucede, la memoria tomada desde Windows, observada a través del Administrador de Tareas, fluctúa de 64MB a 900 + MB en todo el lugar.

ACTUALIZACIÓN 2008-12-18: He ejecutado el programa con -Xms16M -Xmx16M sin ningún efecto adverso aparente - el rendimiento está bien, el tiempo de ejecución total es más o menos el mismo. Pero el uso de la memoria en un corto plazo todavía alcanzó su punto máximo a aproximadamente 180M.

Actualización 2009-01-21: Parece que la respuesta puede estar en el número de subprocesos; consulte mi respuesta a continuación.

EDITAR: Y me refiero a millones de fallas de página, literalmente, en la región de 30M +.

EDITAR: Tengo una máquina 4G, por lo que el 200M no es significativo en ese sentido.


¿Estás utilizando el recopilador ConcMarkSweep? Puede aumentar la cantidad de memoria requerida para su aplicación debido a una mayor fragmentación de la memoria y "basura flotante": objetos que se vuelven inalcanzables solo después de que el recolector los haya examinado y, por lo tanto, no se recopilan hasta la próxima pasada.


¿Mucha memoria asignada fuera del montón de Java después de actualizar a Java 6u10? Solo puede ser una cosa:

Notas de la versión de Java6 u10 : "Nueva canalización de representación acelerada de Direct3D (...) habilitada de forma predeterminada"

Sun habilitó las aceleraciones Direct 3D de forma predeterminada en Java 6u10. Esta opción crea muchos búferes de memoria nativos (¿temporales?), Que se asignan fuera del Heap de Java. Agregue el siguiente argumento vm para deshabilitarlo de nuevo:

-Dsun.java2d.d3d = falso

Tenga en cuenta que esto NO deshabilitará la aceleración de hardware 2D, solo algunas características que pueden hacer uso de la aceleración de hardware 3D. Verás que el uso de tu heap de Java aumentará en hasta 7 MB, pero es una buena solución porque ahorrarás unos 100 MB (+) de esta memoria volátil temporal.

Hice una buena cantidad de pruebas dentro de la aplicación de escritorio 2 Swing, en dos plataformas:

  • una tarjeta gráfica Intel-i7 de alta gama con nVidia GTX 260,
  • una computadora portátil de 3 años con gráficos Intel.

En ambas plataformas de hardware la opción hizo prácticamente cero diferencia subjetiva. (Pruebas incluidas: tablas de desplazamiento, acercamiento de hojas de flujo gráficas, tablas, etc.). En las pocas pruebas en las que algo era sutilmente diferente, la desactivación de d3d incrementó el rendimiento de manera intuitiva. Sospecho que los problemas de gestión de la memoria / ancho de banda contrarrestaron los beneficios que se suponía que las funciones aceleradas d3d debían lograr. (¡Su experiencia puede ser diferente!)

Si necesita realizar algunos ajustes de rendimiento, aquí hay una referencia excelente (por ejemplo, "Solución de problemas de Java 2D")


En las últimas semanas tuve motivos para investigar y corregir un problema con un objeto de agrupamiento de hebras (un grupo de ejecución de subprocesos múltiples anterior a Java 6), donde se estaban iniciando muchos más hilos de los requeridos. En los trabajos en cuestión, podría haber hasta 200 hilos innecesarios. Y los hilos estaban muriendo continuamente y los nuevos reemplazándolos.

Después de haber corregido ese problema, pensé volver a realizar una prueba, y ahora parece que el consumo de memoria es estable (aunque 20 MB más alto que con las JVM antiguas).

Así que mi conclusión es que los picos en la memoria estaban relacionados con la cantidad de subprocesos en ejecución (varios cientos). Desafortunadamente no tengo tiempo para experimentar.

Si alguien quisiera experimentar y responder a esto con sus conclusiones, aceptaré esa respuesta; de lo contrario, aceptaré este (después del período de espera de 2 días).

Además, la tasa de fallas de página está muy baja (por un factor de 10).

Además, las correcciones al grupo de subprocesos corrigieron algunos problemas de contención.


En respuesta a una discusión en los comentarios a la respuesta de Ran, aquí hay un caso de prueba que demuestra que la JVM devolverá la memoria al sistema operativo bajo ciertas circunstancias:

public class FreeTest { public static void main(String[] args) throws Exception { byte[][] blob = new byte[60][1024*1024]; for(int i=0; i<blob.length; i++) { Thread.sleep(500); System.out.println("freeing block "+i); blob[i] = null; System.gc(); } } }

Veo que el tamaño del proceso de JVM disminuye cuando el conteo alcanza alrededor de 40, tanto en JVM Java 1.4 como Java 6 (desde Sun).

Incluso puede ajustar el comportamiento exacto con las opciones -XX: MaxHeapFreeRatio y -XX: MinHeapFreeRatio : algunas de las opciones en esa página también pueden ayudar a responder la pregunta original.


La creación excesiva de hilo explica perfectamente su problema:

  • Cada subproceso obtiene su propia pila, que está separada de la memoria de montón y, por lo tanto, no registrada por los perfiladores
  • El tamaño predeterminado de la pila de subprocesos es bastante grande, IIRC 256 KB (al menos fue para Java 1.3 )
  • La memoria de la pila de rodadura probablemente no se vuelva a utilizar, por lo que si crea y destruye muchos hilos, obtendrá muchas fallas de página

Si alguna vez realmente necesita tener cientos de subprocesos, el tamaño de la pila de subprocesos se puede configurar a través del parámetro de línea de comandos -Xss.


La recolección de basura es una ciencia bastante arcana. A medida que se desarrolle el estado del arte, el comportamiento sintonizado cambiará en respuesta.

Java 6 tiene un comportamiento de GC predeterminado diferente y una "ergonomía" diferente a las versiones anteriores de JVM. Si le dice que puede usar más memoria (ya sea explícitamente en la línea de comando o implícitamente al no especificar nada más explícito), usará más memoria si cree que esto puede mejorar el rendimiento.

En este caso, Java 6 parece creer que reservar el espacio extra en el que podría crecer el montón le dará un mejor rendimiento, presumiblemente porque cree que esto causará que más objetos mueran en el espacio de Edén, y limitará la cantidad de objetos promovidos a el espacio de generación titular. Y a partir de las especificaciones de su hardware, la JVM no cree que este espacio adicional de montón guardado cause ningún problema. Tenga en cuenta que muchas (aunque no todas) las suposiciones que la JVM hace para llegar a su conclusión se basan en aplicaciones "típicas", en lugar de en su aplicación específica. También hace suposiciones basadas en su hardware y perfil de sistema operativo.

Si la JVM ha hecho suposiciones erróneas, puede influir en su comportamiento a través de la línea de comandos, aunque es fácil equivocarse ...

La información sobre los cambios de rendimiento en java 6 se puede encontrar here .

Hay una discusión sobre la administración de la memoria y las implicaciones de rendimiento en el Libro Blanco de administración de memoria .


No sé sobre las fallas de página. pero sobre la gran memoria asignada para Java:

  1. La JVM de Sun solo asigna memoria, nunca la desasigna (hasta la muerte de JVM) desasigna memoria solo después de que una relación específica entre las necesidades de memoria interna y la memoria asignada cae por debajo de un valor (ajustable). La JVM comienza con la cantidad especificada en -Xms y puede extenderse hasta la cantidad especificada en -Xmx. No estoy seguro de cuáles son los valores predeterminados. Cada vez que la JVM necesita más memoria (nuevos objetos / primitivas / matrices) asigna un fragmento completo del sistema operativo. Sin embargo, cuando la necesidad disminuye (una necesidad momentánea, vea también 2) no desasigna la memoria al sistema operativo inmediatamente , sino que la mantiene a sí misma hasta que se alcanza esa proporción. Una vez me dijeron que JRockit se comporta mejor, pero no puedo verificarlo.

  2. La JVM de Sun ejecuta un GC completo basado en varios factores desencadenantes. Una de ellas es la cantidad de memoria disponible: cuando baja demasiado, la JVM intenta realizar un GC completo para liberar un poco más. Entonces, cuando se asigna más memoria desde el sistema operativo (necesidad momentánea), se reduce la posibilidad de un GC completo. Esto significa que si bien puede ver 30Mb de objetos "vivos", puede haber muchos más objetos "muertos" (no alcanzables), solo esperando que ocurra un CG. Sé que tu kit tiene una gran vista llamada "objetos muertos" donde puedes ver estos "sobrantes".

  3. En el modo "-server", la JVM de Sun ejecuta GC en modo paralelo (a diferencia de la serie anterior "stop the world" GC). Esto significa que si bien puede haber basura para recopilar, es posible que no se recopile inmediatamente porque otros subprocesos tardan todo el tiempo de CPU disponible. Se recopilará antes de que se agote la memoria (bueno, un poco. Vea http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html ), si se puede asignar más memoria desde el SO, podría estar antes de que el GC se ejecute.

Combinados, una configuración de memoria inicial grande y ráfagas cortas que crean una gran cantidad de objetos efímeros podrían crear un escenario como se describe.

edit: cambió "never deallcoates" a "only after ratio alcanzado".