java - usar - Fuga de memoria sin que los objetos crezcan en número o tamaño
usar usb como ram windows 10 (3)
En un sistema IBM iSeries, tengo un programa Java en ejecución: un servidor de aplicaciones con un componente de servidor web, todo desarrollado internamente. Cuando se ejecuta en la JVM J9 de 32 o 64 bits (Tecnología IBM para Java) tengo síntomas de una pérdida de memoria.
Tenga en cuenta que no se observan problemas al ejecutar este software en la JVM clásica iSeries, en múltiples JVM Sun / Oracle y en JVM Linux. Demonios, de manera rutinaria, dejo correr el software idéntico durante semanas en el portátil de nivel inicial de mi esposa mientras trabajo en mi sitio web. Puedo asegurarle que si se estuviera perdiendo la memoria se notaría en esa cosa.
Si simplemente dejo inactivo un sistema simple de vainilla, sin aplicaciones configuradas (básicamente solo el sistema de mensajería y un servidor web), el montón continúa creciendo lentamente, causando que se asigne más memoria a lo largo del tiempo, con cada ciclo de GC no bastante recogiendo hasta el nivel anterior. El patrón es exactamente el mismo para las JVM en las que no hay ningún problema, excepto que, en ellas, el barrido del GC siempre reduce el montón a su nivel de GC anterior.
Pero, si jalo un volcado del sistema JVM al inicio después de la estabilización y los volcados subsiguientes después de que el montón asignado haya crecido significativamente, la comparación diferencial indica que no hay objetos más accesibles después de ejecutar durante una semana de lo que había al inicio. El más reciente, después de una semana, muestra 6 clases adicionales cargadas y algunos objetos claramente relacionados con eso. Las revisiones exhaustivas de todos los objetos vivos no han mostrado nada que salte de mí como inesperado.
He probado el recolector de basura optimizado para el rendimiento y el generacional-concurrente.
Entonces, de acuerdo con el tamaño del montón del trabajo, parece que tenemos una fuga, y de acuerdo con los botaderos del montón, no hay fugas.
No se están invocando métodos JNI (aparte del código nativo que se ejecuta como parte de la JVM central), y definitivamente es el montón el que está creciendo. Puedo verlo claramente en la información de IBM WRKJVMJOB y también se informa sobre el uso de beans JMX en mi consola archivo de registro.
Hasta ahora no puedo conectarme a la JVM activa utilizando herramientas JMX como JVisualVM porque, aunque el socket de escucha se crea cuando está configurado correctamente, la conexión se rechaza, aparentemente a nivel de protocolo (la pila TCP / IP muestra una conexión aceptada, pero la JVM lo rebota).
Estoy confundido, y sin saber dónde ir a continuación.
EDITAR: Sólo para aclarar; estos resultados son todos con una JVM sin instrumentos porque no puedo obtener acceso de JMX a esta JVM (estamos trabajando en eso con IBM).
EDITAR 2011-11-16 19:27: Pude obtener un informe de actividad de GC sobre 1823 ciclos de GC que incluye recuentos específicos para recuentos de Referencia suave / débil / fantasma; no hay señales de crecimiento descontrolado en esos números. Sin embargo, hay un crecimiento significativo en el espacio de tenencia de objeto pequeño (el espacio de tenencia de objeto grande está vacío). Se cultiva de 9M a 36M.
Después de haber eliminado algunos desperdicios de memoria por descuido (aunque no de fugas) en mi programa, y sintonizado mejor el GC para nuestra carga de trabajo, he reducido el uso de la memoria fuera de control a un nivel tolerable.
Sin embargo, en el proceso, he demostrado que la JVM IBM J9 utilizada en el AS / 400 (también conocido como iSeries, Systemi, i5, etc.) tiene una fuga de 1336 bytes / minuto que totaliza 2 MB / día. Puedo observar esta fuga con una variedad de programas desde un programa de prueba de "una línea" hasta nuestro servidor de aplicaciones.
El programa de prueba de una línea es este:
public class ZMemoryLeak2
extends Object
{
static public synchronized void main(String... args) {
try { ZMemoryLeak2.class.wait(0); } catch(InterruptedException thr) { System.exit(0); }
}
}
Y un programa de prueba independiente que no hizo nada excepto el uso de la memoria del monitor a través de la API JMX mostró de manera concluyente que 1336 B se filtró en intervalos de exactamente 1 minuto, nunca se recuperará (bueno, no se recuperará después de 2 semanas de funcionamiento). Nota de OP: En realidad, fue una cantidad ligeramente diferente en cada variación de la JVM.
Actualización 2012-04-02 : Esto fue aceptado como un error por IBM hace unas semanas; en realidad fue encontrado y parcheado en Java 5 a mediados del año pasado, y se espera que el parche para Java 6 esté disponible en la próxima semana o dos.
Gran pregunta Pensé en convertir algunos de mis comentarios en una respuesta.
Usted menciona que un sistema inactivo crece en términos de memoria. Este es un bit importante de información. O bien hay algunos trabajos programados internos (automatizaciones, temporizadores, etc.) o el monitoreo de procesos externos que está causando el ancho de banda del objeto. Consideraría desactivar el monitoreo para ver si los gráficos están afectados. Esto puede ayudarlo a determinar qué objetos son parte del problema.
Cuando el objeto está bajo carga, sospecho que hay una cierta cantidad de ancho de banda de objeto. Su problema final puede ser que la JVM de IBM no maneje la fragmentación de la memoria, así como las otras JVM, aunque esto me sorprende. Trabajaría con ellos para probar otras opciones de GC para ver cómo puede abordar esto. Pensaría que esto sería fácil de simular si escribiera un servidor de prueba que hiciera un montón de operaciones de memoria y viera si con el transcurso de los días el uso de la memoria aumenta. Esto puede demostrar que es hora de migrar fuera de las JVM de IBM. Nuevamente, esto me sorprendería, pero si lo que dice es cierto y el número o tamaño de los objetos no aumenta ...
Me gustaría ver los gráficos de las distintas secciones de memoria. Sospecho que está viendo subir y bajar el espacio de la vieja generación y que el sobreviviente va aumentando constantemente. Si es cierto que la cantidad de objetos no está cambiando, @Stephen debe tener razón sobre su tamaño interno o algo más en el trabajo. Tal vez la contabilidad de objetos no está reportando a todos por alguna razón.
Encuentro que el botón gc JMX en la pestaña de memoria hace un barrido más completo. Debería ser equivalente a usar
System.gc()
que ha intentado. Solo para tu información.Sería bueno activar la salida de registro del GC para ver si puede ver algún patrón: http://christiansons.net/mike/blog/2008/12/java-garbage-collection-logging/ y http://java.sun.com/developer/technicalArticles/Programming/GCPortal/
¿Hay alguna posibilidad de que pueda aumentar el rendimiento de las transacciones en el servidor sin cambiar la supervisión o las automatizaciones internas? Si ve que los gráficos de la memoria cambian en pendiente, entonces sabe que se basa en transacciones. Si no, entonces tus problemas están en otra parte. Nuevamente, esto es para ayudarlo a encontrar qué objetos pueden estar causando problemas.
Espero que algo aquí sea útil.
Una posible explicación es que está viendo la acumulación de objetos en un caché implementado utilizando WeakReference
o similar. El escenario es el siguiente:
Los ciclos de GC que ve en el gráfico son colecciones del nuevo espacio y no causan que las referencias se rompan. Así que el caché continúa creciendo y utilizando más espacio de almacenamiento dinámico.
Cuando toma una instantánea, esto hace que se ejecute un GC completo que (tal vez) rompe las referencias y libera los objetos en caché.
(Note el "tal vez". No estoy seguro de que esta explicación contenga agua ...)
Otra posible explicación es que su aplicación tiene la misma cantidad de objetos, pero algunos de ellos son más grandes. Por ejemplo, puede tener una matriz de algún tipo primitivo que sigue reasignando con un tamaño mayor. O un StringBuilder / StringBuffer sigue creciendo. O (en algunas circunstancias) una ArrayList o similar que sigue creciendo.
Sabes, podrías estar persiguiendo a un fantasma aquí. Puede ser que el volcado del sistema esté diciendo la verdad y que no haya ninguna fuga de almacenamiento. Podría probar esa teoría reduciendo el tamaño del montón a un punto en el que una pérdida de memoria real pueda provocar un OOME con relativa rapidez. Si no pudiera provocar un OOME de esa manera, me sentiría inclinado a escribir esto como una curiosidad interesante ... y pasar a un problema real.