¿Por qué la Sun JVM sigue consumiendo cada vez más memoria RSS incluso cuando los tamaños del montón, etc. son estables?

Durante el año pasado, realicé enormes mejoras en el uso del montón de Java de mi aplicación: una sólida reducción del 66%. En pos de eso, he estado monitoreando varias métricas, como el tamaño del montón de Java, la CPU, el no de Java, etc. a través de SNMP.

Recientemente, he estado monitoreando la cantidad de memoria real (RSS, conjunto residente) de la JVM y estoy algo sorprendido. La memoria real consumida por la JVM parece totalmente independiente del tamaño de pila de mis aplicaciones, no de pila, espacio eden, conteo de hilos, etc.

Tamaño del montón medido por Java SNMP Java Heap Used Graph http://lanai.dietpizza.ch/images/jvm-heap-used.png

Memoria real en KB. (Por ejemplo: 1 MB de KB = 1 GB) Java Heap Used Graph http://lanai.dietpizza.ch/images/jvm-rss.png

(Las tres inmersiones en el gráfico del montón corresponden a actualizaciones / reinicios de la aplicación).

Esto es un problema para mí porque toda la memoria adicional que consume la JVM es la memoria de "robo" que el sistema operativo podría utilizar para el almacenamiento en caché de archivos. De hecho, una vez que el valor RSS alcanza ~ 2.5-3GB, comienzo a ver tiempos de respuesta más lentos y una mayor utilización de la CPU en mi aplicación, principalmente para esperar a IO. A medida que se inicia la paginación de puntos a la partición de intercambio, todo esto es muy indeseable.

Entonces, mis preguntas:

¿Por qué está pasando esto? Que esta pasando"bajo el capó"?¿Qué puedo hacer para controlar el consumo de memoria real de la JVM?

Los detalles sangrientos:

RHEL4 de 64 bits (Linux - 2.6.9-78.0.5.ELsmp # 1 SMP, miércoles, 24 de septiembre de 2008 x86_64 ... GNU / Linux)Java 6 (compilación 1.6.0_07-b06)Tomcat 6Aplicación (transmisión de video HTTP bajo demanda)Alta I / O vía java.nio FileChannelsCientos a bajo miles de hilos.Bajo uso de base de datosPrimavera, Hibernate

Parámetros JVM relevantes:

-Xms128m  
-Xmx640m  
-XX:+UseConcMarkSweepGC  
-XX:+AlwaysActAsServerClassMachine  
-XX:+CMSIncrementalMode    

-XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps  
-XX:+PrintGCApplicationStoppedTime  
-XX:+CMSLoopWarn  
-XX:+HeapDumpOnOutOfMemoryError 

Cómo mido RSS:

ps x -o command,rss | grep java | grep latest | cut -b 17-

Esto se incluye en un archivo de texto y se lee en una base de datos de RRD en el sistema de monitoreo en intervalos regulares. Tenga en cuenta que las salidas ps Kilo Bytes.

El problema y la solucións:

Mientras que al final eraAtorrasLa respuesta que finalmente resultó correcta,kdgregory quien me guió a la ruta correcta de diagnóstico con el uso depmap. (¡Vota por las dos respuestas!) Esto es lo que estaba sucediendo:

Cosas que sé con seguridad:

Mi aplicación graba y muestra datos conJRobin 1.4, algo que codifiqué en mi aplicación hace más de tres años.La instancia más ocupada de la aplicación crea actualmenteMás de 1000 archivos de base de datos de JRobin nuevos (aproximadamente a 1.3 MB cada uno) dentro de una hora de inicio~ 100 + cada día después de la puesta en marchaLa aplicación actualiza estos objetos de la base de datos JRobin una vez cada 15 s, si hay algo que escribir.En la configuración por defecto JRobin:utiliza unjava.niobasado en el acceso de archivos de fondo. Este back-end mapasMappedByteBuffers a los propios archivos.una vez cada cinco minutos un subproceso de JRobin llamaMappedByteBuffer.force() en cada base de datos subyacente de JRobin MBBpmap listado:6500 mapeos5500 de los cuales eran archivos de base de datos JRobin de 1.3MB, lo que equivale a ~ 7.1GB

Ese último punto fue mi"Eureka!" momento.

Mis acciones correctivas:

Considera actualizar a la última versión de JRobinLite 1.5.2 que aparentemente es mejorImplementar el manejo adecuado de los recursos en las bases de datos JRobin. En este momento, una vez que mi aplicación crea una base de datos y luego nunca la descarga, la base de datos ya no se usa activamente.Experimenta moviendo elMappedByteBuffer.force() a los eventos de actualización de la base de datos, y no un temporizador periódico. ¿El problema desaparecerá mágicamente?Inmediatamente, cambie el back-end de JRobin a la implementación de java.io, un cambio de línea. Esto será más lento, pero posiblemente no sea un problema. Aquí hay una gráfica que muestra el impacto inmediato de este cambio.

La memoria RSS de Java utiliza el gráfico http://lanai.dietpizza.ch/images/stackoverflow-rss-problem-fixed.png

Preguntas que puedo o no tener tiempo para resolver:

¿Qué está pasando dentro de la JVM conMappedByteBuffer.force()? Si nada ha cambiado, ¿sigue escribiendo todo el archivo? ¿Parte del archivo? ¿Lo carga primero?¿Hay una cierta cantidad de MBB siempre en RSS en todo momento? (RSS fue aproximadamente la mitad del total de tamaños de MBB asignados. ¿Coincidencia? Sospecho que no).Si muevo elMappedByteBuffer.force() a los eventos de actualización de la base de datos, y no a un temporizador periódico, ¿desaparecerá mágicamente el problema?¿Por qué la pendiente RSS era tan regular? No se correlaciona con ninguna de las métricas de carga de la aplicación.

Respuestas a la pregunta(4)

Su respuesta a la pregunta