2010-01-08 23 views
6

Tengo una aplicación de Java en ejecución, que estoy monitoreando con visualVM.Posible fuga de memoria?

Así es el gráfico de la pila:

heap http://www.freeimagehosting.net/uploads/9bb3841450.png

La fue probado con dos juegos de peticiones, uno a las 3:20 y la otra a 04:40 aprox (que están representadas en el gráfico como los únicos dos picos).

Mi pregunta es: ¿significa esto que tengo una pérdida de memoria? Me preocupa la parte central donde, aunque el GC funciona, el montón se mantiene en 250 MB todo el tiempo.

Muchas gracias por su conocimiento.

+1

Un tamaño de muestra de 2 realmente no proporciona suficiente información para declarar una fuga. Sí, uno podría estar oculto en ese gráfico: el tamaño asignado a la derecha es más grande que el de la izquierda. O podría, como se mencionó * binil *, ser solo que algunos objetos fueron promovidos a la generación titular y no tenías un GC importante. – kdgregory

+0

Realmente, la única manera de determinar si tiene una fuga es comparar el número de objetos en vivo retenidos a lo largo del tiempo. Publiqué un artículo (aquí) (http://www.kdgregory.com/index.php?page=java.outOfMemory) que habla sobre cómo analizar un volcado de pila. – kdgregory

Respuesta

5

La primera solicitud a las 3:20 causó que se retenga algo de memoria, pero tenga en cuenta que los GC después de la segunda solicitud recuperaron la mayor parte. También creo que el GC principal se realizó solo después de la segunda solicitud a las 4:40.

Parece que no hay fugas. Mi teoría es que la solicitud a las 3:20 provocó que la generación joven se llenara, y el GC menor resultante promovió algunos objetos a la generación anterior. El siguiente gran GC, causado por la solicitud a las 4:40, limpió la mayoría de ellos.

Puede verificar esto utilizando un generador de perfiles para marcar el montón antes de emitir la misma solicitud que la de 3:20, forzando un GC completo, y luego verificando qué objetos están detenidos. No estoy seguro si VisualVM te permite (1) marcar el montón y (2) forzar un GC completo, pero OptimizeIt solía hacerlo.

+0

Muchas gracias binil. ¿Podría indicarme una buena documentación de referencia para poner al día todos esos conceptos? (generación joven, generación anterior, diferentes tipos de ejecuciones de GC, etc.) –

+1

http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html podría ayudar –

+0

De hecho, un examen adicional con 'visualGC' el complemento mostró que los objetos se promovieron a la otra parte del montón. –

0

¿Está diciendo que no había solicitudes antes de las 3:20? Si es así, entonces diría que no veo ninguna evidencia de una fuga.

No conozco su aplicación, pero es típico (según la arquitectura/diseño) que algunos objetos que se almacenan durante la vida de la JVM se inicialicen cuando la aplicación se utiliza por primera vez.

0

¿Qué JRE estás usando? ¿Qué parámetros relevantes de heap/GC se pasan a la aplicación?

El pico no está mal (si había más tareas pendientes para el servidor, tiene sentido que el pico aumente). Pero lo que no se ve tan bien es que el nivel después de 4:40 (cuando la carga está baja nuevamente) es más alto a medida que el nivel antes de la carga aumentaba. Pero no es necesario que sea ...

Ahora debería ver más detalles, qué objetos u objetos-gráficos se guardan en el montón. Lo mismo ocurre con la misma ejecución del ensayo incluyendo de nuevo (con perfilador):

  • tomar una instantánea del montón antes de la carga sube
  • tomar una instantánea montón después de la carga baja (asegúrese de hacer un disparador GC manual)

Ahora debe analizar los diffs y si ve objetos extraños, que deberían haber sido guardados.

0

JvisualVM le permite forzar una recolección de basura.

Intenta usar eso para ver qué pasa.

+0

¿Realmente lo fuerza o llama a System.gc()? –

+0

Creo que lo fuerza. Tal vez solo sea Sun JVM. –

+0

Realmente llama a 'System.gc()' no obliga a nada. –

-1

¿Qué quiere decir con pérdida de memoria aquí? No creo que ninguna implementación JVM como SUN tenga un error tan loco.la palabra de fuga de memoria se usa idealmente cuando no se hace referencia a una ubicación de memoria (zombie) o no se tiene la posibilidad de reclamarla. Si tiene una práctica de programación incorrecta en la que hace referencia a objetos que ya no están en uso y que tienen un alcance mayor (vida útil), entonces consume más memoria sin dar al GC la opción de volver a recopilarla.