2010-11-24 10 views
7

Si, en efecto, se crea una aplicación que cruje los datos mientras que sufren de memoria-fugas, puedo notar que la memoria según lo informado por, digamos:La detección de la memoria de fugas mediante programación

Runtime.getRuntime().freeMemory() 

comienza a oscilar entre 1 y 2 MB de memoria libre.

La aplicación luego ingresa en un bucle que dice así: GC, procesando algunos datos, GC, etc. pero debido a que el GC ocurre con tanta frecuencia, la aplicación básicamente ya no hace mucho más. Incluso la GUI tarda años en responder (y, no, no estoy hablando de los problemas de EDT aquí, en realidad es la máquina virtual básicamente atrapada en un modo interminable de GC).

Y me preguntaba: ¿hay alguna forma de detectar mediante programación que la JVM ya no tiene suficiente memoria?

Tenga en cuenta que no estoy hablando de errores de memoria insuficiente ni de detectar la pérdida de memoria en sí.

Estoy hablando de detectar que una aplicación tiene tan poca memoria que básicamente está llamando al GC todo el tiempo, dejando casi ningún momento para hacer otra cosa (en mi ejemplo hipotético: datos crujientes).

¿Funcionaría, por ejemplo, leer repetidamente la cantidad de memoria disponible durante, digamos, un minuto, y ver si el número ha estado "oscilando" entre diferentes valores, digamos 4 MB, y concluye que ¿Ha habido alguna fuga y la aplicación se ha vuelto inutilizable?

+2

creo una mejor idea sería fijar tu codigo. –

+3

@San Jacinto: la falta de visión de su comentario es atractiva y no contribuye en nada a SO. Es probable que desee volver a leer la pregunta y la respuesta en caso de que tenga algo valioso para proporcionar en SO. – SyntaxT3rr0r

+3

Solo cuando es tu código el que está actuando. No todo el software de terceros se crea igual, no por una posibilidad remota. Pensé que había un gancho de GC en el que podrías conectar ... déjame ver ... –

Respuesta

0

Puede pasar argumentos a la máquina virtual de Java que proporciona diagnósticos GC como

  1. -verbose:gc Esta bandera se convierte en el registro de la información de GC. Disponible en todas las JVM.

  2. -XX:+PrintGCTimeStamps imprime las horas a las que suceden los CG en relación con el inicio de la aplicación .

Si captura que la salida en un archivo, en su aplicación se puede leer periodcly ese archivo y analizarlo para saber cuando el GC ha sucedido. Para que pueda calcular el tiempo promedio entre cada GC

3

Y me preguntaba: ¿hay alguna forma de detectar mediante programación que la JVM ya no tiene suficiente memoria?

No lo creo. Puede averiguar aproximadamente cuánta memoria Heap es gratuita en un instante dado, pero AFAIK no puede determinar de manera confiable cuándo se está quedando sin memoria. (Claro, puede hacer cosas como raspar los archivos de registro de GC o tratar de elegir patrones en las oscilaciones de memoria libres. Pero es probable que sean poco fiables y frágiles frente a los cambios de JVM).

Sin embargo, existe otro (y mejor IMO) enfoque.

En versiones recientes de Hotspot (versión 1.6 y posteriores, creo), puede sintonizar la JVM/GC para que se rinda y arroje un OOME antes.Específicamente, la JVM puede ser configurado para verificar que:

  • la relación del montón libre de montón total es mayor que un umbral dado después de un GC completo, y/o
  • el tiempo pasado de ejecutar el GC es menos que un cierto porcentaje del total.

Los parámetros de JVM relevantes son "UseGCOverheadLimit", "GCTimeLimit" y "GCHeapFreeLimit". Desafortunadamente, los parámetros de ajuste de Hotspot no están bien documentados en la web pública, pero estos están listados here.

Suponiendo que desea que su aplicación haga lo sensato ... renuncie cuando ya no tenga suficiente memoria para ejecutarse correctamente ... entonces simplemente inicie la JVM con un "GCTimeLimitor" o "GCHeapFreeLimit" más pequeño que los valores predeterminados.

EDITAR

he descubierto que el MemoryPoolMXBean API le permite buscar en el uso máximo de los bloques de memoria individuales (pilas) y conjunto de umbrales. Sin embargo, nunca lo he probado, y las API tienen muchas sugerencias que sugieren que no todas las JVM implementan la API completa. Por lo tanto, aún recomendaría el enfoque de opción de ajuste HotSpot (ver arriba) sobre este.

+0

+1, leeré el documento en estas JVM parámetros, se ven muy interesantes ... – SyntaxT3rr0r

1

Veo dos vectores de ataque.

Cualquiera de los dos monitoree su consumo de memoria.

Cuando usa más o menos constantemente mucha de la memoria disponible, es muy probable que tenga una pérdida de memoria (o que esté utilizando demasiada memoria). El vm intentará constantemente liberar algo de memoria sin mucho éxito => uso de memoria constante.

Debe distinguirlo de un patrón en zigzag grande que ocurre a menudo sin ser un indicador de problema de memoria. Básicamente, usted usa más y más memoria, pero cuando gc encuentra tiempo para hacer su trabajo, encuentra mucha basura para llevar a cabo, así que todo está bien.

El otro vector de ataque es controlar la frecuencia y el tipo de éxito que ejecuta el gc. Si se ejecuta a menudo con solo pequeñas ganancias en la memoria, es probable que tenga un problema.

No sé si puede acceder a este tipo de información directamente desde su programa. Pero si nada más creo que puede especificar parámetros en el inicio que hace que la información de registro de gc en un archivo que a su vez podría ser analizado.

+0

+1 ... Sobre el zigzag grande, es por eso que estaba pensando en considerar que hay un problema si todas las lecturas son muy cercanas y todas dan menos de 'X' MB menos. – SyntaxT3rr0r

2

Puede usar getHeapMemoryUsage.

+0

De acuerdo. JMX está diseñado para tal punto. –

+0

Sin embargo, esto no le brinda la información que necesita saber para evitar la vibración del GC; es decir, cuánta memoria estaba libre/en uso inmediatamente después del último GC completo. Para eso, necesitaría usar los métodos de umbral/notificación de MemoryPoolMXBean ... si es compatible. –

1

Lo que podría hacer es engendrar un hilo que se despierta periódicamente y calcula la cantidad de memoria utilizada y registra el resultado. Luego puede hacer regression analysis en el resultado para estimar la velocidad de crecimiento de la memoria en su aplicación. Si conoce la tasa de crecimiento y la cantidad máxima de memoria, puede predecir (con cierta confianza) cuándo se agotará la memoria de su aplicación.

+0

esta es una muy buena idea también. No estoy seguro de que el crecimiento sea lineal, dijo, pero me gusta mucho esta idea. – SyntaxT3rr0r

+0

Es muy probable que el crecimiento no sea lineal :), pero sé por experiencia que si esto se implementa bien, los resultados son significativos. –

0

Creo que la JVM hace exactamente esto por usted y arroja java.lang.OutOfMemoryError: GC overhead limit exceeded. Entonces, si tomas OutOfMemoryError y buscas ese mensaje, entonces tienes lo que quieres, ¿no?

Ver this question para más detalles

+0

oh no no no ... En algunos casos se encontrará con el escenario que describí: GC, procesando algunos datos, GC, procesando algunos datos. Técnicamente, la JVM todavía se está ejecutando pero, en la práctica, es tan lento como la melaza que podrías matar la aplicación. Claro, en muchos casos obtendrás el OOM pero en algunos casos obtendrás exactamente lo que describí. – SyntaxT3rr0r

0

He estado usando plumbr para la detección de pérdida de memoria y ha sido una gran experiencia, aunque la licencia es muy caro: http://plumbr.eu/

Cuestiones relacionadas