Es casi imposible sin alguna comprensión del código subyacente. Si comprende el código subyacente, entonces puede ordenar mejor el trigo de la chatarra de los tropecientos trillizos de información que está obteniendo en sus vertederos.
Además, no se puede saber si algo es una fuga o no, sin saber por qué la clase está allí en primer lugar.
Acabo de pasar las últimas dos semanas haciendo exactamente esto, y utilicé un proceso iterativo.
Primero, los perfiladores de montón me parecieron básicamente inútiles. No pueden analizar los montones enormes de manera eficiente.
Más bien, me basé casi exclusivamente en jmap histogramas.
me imagine que está familiarizado con estos, pero para los que no:
jmap -histo:live <pid> > dump.out
crea un histograma de la pila en vivo. En pocas palabras, te dice los nombres de las clases, y cuántas instancias de cada clase están en el montón.
Estaba abandonando montón regularmente, cada 5 minutos, 24 horas al día. Eso puede ser demasiado granular para ti, pero la esencia es la misma.
Realicé varios análisis diferentes de estos datos.
Escribí un script para tomar dos histogramas y eliminar la diferencia entre ellos. Entonces, si java.lang.String fuera 10 en el primer volcado y 15 en el segundo, mi secuencia de comandos escupiría "5 java.lang.String", y me dijo que subió 5 veces. Si se hubiera reducido, el el número sería negativo.
Entonces tomaría varias de estas diferencias, eliminaría todas las clases que pasaron de ejecución a ejecución y tomaré una unión del resultado. Al final, tendría una lista de clases que crecía continuamente en un lapso de tiempo específico. Obviamente, estos son los principales candidatos para las clases con pérdidas.
Sin embargo, algunas clases tienen algunas conservadas mientras que otras son GC'd. Estas clases podrían subir y bajar fácilmente en general, y aun así tener fugas. Por lo tanto, podrían caerse de la categoría de clases "siempre ascendente".
Para encontrarlos, convertí los datos en una serie temporal y la cargué en una base de datos, específicamente Postgres. Postgres es útil porque ofrece statistical aggregate functions, por lo que puede hacer simple linear regression analysis en los datos, y encontrar clases que tienden hacia arriba, incluso si no siempre están en la parte superior de los gráficos. Usé la función regr_slope, buscando clases con una pendiente positiva.
Encontré este proceso muy exitoso y realmente eficiente. Los archivos de histogramas no son increíblemente grandes y fue fácil descargarlos de los hosts. No eran demasiado caros para funcionar en el sistema de producción (forzaron un GC grande y pueden bloquear la VM por un tiempo). Estaba ejecutando esto en un sistema con un montón Java 2G.
Ahora, todo lo que se puede hacer es identificar las clases potencialmente con fugas.
Aquí es donde se entiende cómo se usan las clases, y si deberían o no deberían ser suyas.
Por ejemplo, es posible que tenga muchas clases de Map.Entry o alguna otra clase de sistema.
A menos que simplemente esté almacenando en caché String, el hecho es que estas clases de sistema, aunque quizás los "delincuentes", no son el "problema". Si está almacenando en caché alguna clase de aplicación, ESA clase es un mejor indicador de dónde reside su problema. Si no almacena en caché com.app.yourbean, entonces no tendrá asociado Map.Entry.
Una vez que tenga algunas clases, puede comenzar a rastrear el código base buscando instancias y referencias. Como tiene su propia capa de ORM (para bien o para mal), al menos puede mirar fácilmente el código fuente. Si ORM está almacenando en caché cosas, es probable que almacene en caché las clases de ORM que envuelven sus clases de aplicación.
Finalmente, otra cosa que puede hacer, una vez que conozca las clases, puede iniciar una instancia local del servidor, con un montón mucho más pequeño y un conjunto de datos más pequeño, y utilizando uno de los perfiles contra eso.
En este caso, puede realizar una prueba unitaria que afecte solo a 1 (o a un número pequeño) de las cosas que cree que pueden estar filtrando. Por ejemplo, puede iniciar el servidor, ejecutar un histograma, realizar una sola acción y ejecutar el histograma de nuevo. Tu clase de fuga debería haber aumentado en 1 (o lo que sea que sea tu unidad de trabajo).
Un generador de perfiles puede ayudarlo a rastrear a los propietarios de esa clase "ahora filtrada".
Pero, al final, vas a tener que entender algo de tu código base para comprender mejor qué es una fuga y qué no, y por qué existe un objeto en el montón, y mucho menos por qué puede estar siendo retenido como una fuga en tu montón.
Compré más memoria – LB40
@LB Tenemos 64 GB, pero el presupuesto para esta aplicación es de solo 2 GB, y no podemos aumentar razonablemente más de un par de GB sin comenzar a canibalizar en otros subsistemas. –
Los volcados de montón son específicos de JVM, por lo tanto, debe utilizar la herramienta adecuada para la JVM en cuestión. ¿Es? –