¿Cómo encuentra una pérdida de memoria en Java (usando, por ejemplo, JHat)? He intentado cargar el volcado del montón en JHat para echar un vistazo básico. Sin embargo, no entiendo cómo se supone que puedo encontrar la referencia raíz ( ref ) o como se llame. Básicamente, puedo decir que hay varios cientos de megabytes de entradas en la tabla hash ([java.util.HashMap $ Entry o algo así), pero los mapas se usan por todas partes ... ¿Hay alguna forma de buscar mapas grandes? , o tal vez encontrar raíces generales de árboles de objetos grandes?
[Editar] Ok, he leído las respuestas hasta ahora, pero digamos que soy un bastardo barato (lo que significa que estoy más interesado en aprender a usar JHat que pagar por JProfiler). Además, JHat siempre está disponible ya que es parte del JDK. A menos que, por supuesto, JHat no tenga otra forma que la fuerza bruta, pero no puedo creer que ese sea el caso.
Además, no creo que pueda modificar (agregar el registro de todos los tamaños de mapas) y ejecutarlo durante el tiempo suficiente para que note la fuga.
fuente
Respuestas:
Utilizo el siguiente enfoque para encontrar pérdidas de memoria en Java. He usado jProfiler con gran éxito, pero creo que cualquier herramienta especializada con capacidades gráficas (las diferencias son más fáciles de analizar en forma gráfica) funcionará.
Básicamente, el análisis debe comenzar desde la mayor diferencia positiva, por ejemplo, por tipos de objeto y encontrar qué causa que esos objetos adicionales se peguen en la memoria.
Para las aplicaciones web que procesan solicitudes en varios subprocesos, el análisis se vuelve más complicado, pero aún así se aplica un enfoque general.
Realicé bastantes proyectos específicamente destinados a reducir la huella de memoria de las aplicaciones y este enfoque general con algunos ajustes y trucos específicos de la aplicación siempre funcionó bien.
fuente
Interrogador aquí, debo decir que obtener una herramienta que no demore 5 minutos en responder cualquier clic hace que sea mucho más fácil encontrar posibles pérdidas de memoria.
Dado que la gente sugiere varias herramientas (solo probé visual wm desde que lo obtuve en la prueba JDK y JProbe), aunque debería sugerir una herramienta de código abierto / libre construida en la plataforma Eclipse, el Analizador de Memoria (a veces referido como la memoria SAP analizador) disponible en http://www.eclipse.org/mat/ .
Lo que es realmente genial de esta herramienta es que indexó el volcado del montón cuando lo abrí por primera vez, lo que le permitió mostrar datos como el montón retenido sin esperar 5 minutos para cada objeto (casi todas las operaciones fueron toneladas más rápidas que las otras herramientas que probé) .
Cuando abre el volcado, la primera pantalla le muestra un gráfico circular con los objetos más grandes (contando el montón retenido) y uno puede navegar rápidamente hacia los objetos que son demasiado grandes para su comodidad. También tiene un hallazgo de posibles sospechosos de fugas que puedo recordar, pero como la navegación fue suficiente para mí, realmente no me metí en eso.
fuente
HeapDumpOnCtrlBreak
parámetro VM no está disponible . La solución que he encontrado (hasta ahora, aún buscando) es usar JMap para volcar el.hprof
archivo, que luego puse en Eclipse y uso MAT para examinar.Una herramienta es de gran ayuda.
Sin embargo, hay momentos en los que no puede usar una herramienta: el volcado de almacenamiento dinámico es tan grande que bloquea la herramienta, está tratando de solucionar problemas de una máquina en algún entorno de producción al que solo tiene acceso de shell, etc.
En ese caso, es útil conocer el archivo de volcado hprof.
Busque SITIOS COMIENZAN. Esto le muestra qué objetos están usando más memoria. Pero los objetos no se agrupan únicamente por tipo: cada entrada también incluye una identificación de "rastreo". Luego puede buscar ese "TRACE nnnn" para ver los pocos fotogramas superiores de la pila donde se asignó el objeto. A menudo, una vez que veo dónde está asignado el objeto, encuentro un error y termino. Además, tenga en cuenta que puede controlar cuántos fotogramas se graban en la pila con las opciones de -Xrunhprof.
Si revisa el sitio de asignación y no ve nada malo, debe comenzar el encadenamiento hacia atrás de algunos de esos objetos vivos a objetos raíz, para encontrar la cadena de referencia inesperada. Aquí es donde una herramienta realmente ayuda, pero puede hacer lo mismo a mano (bueno, con grep). No hay un solo objeto raíz (es decir, un objeto no sujeto a recolección de basura). Los subprocesos, las clases y los marcos de pila actúan como objetos raíz, y cualquier cosa a la que hagan referencia con fuerza no es coleccionable.
Para hacer el encadenamiento, busque en la sección HEAP DUMP las entradas con la identificación de seguimiento incorrecta. Esto lo llevará a una entrada OBJ o ARR, que muestra un identificador de objeto único en hexadecimal. Busque todas las apariciones de esa identificación para encontrar quién tiene una fuerte referencia al objeto. Siga cada uno de esos caminos hacia atrás a medida que se ramifican hasta que descubra dónde está la fuga. ¿Ves por qué una herramienta es tan útil?
Los miembros estáticos son reincidentes por pérdidas de memoria. De hecho, incluso sin una herramienta, valdría la pena pasar unos minutos buscando miembros estáticos en el mapa a través de su código. ¿Puede crecer un mapa? ¿Algo alguna vez limpia sus entradas?
fuente
jhat
yMAT
aparentemente trato de cargar todo el volcado de almacenamiento dinámico en la memoria, por lo que normalmente se bloquea conOutOfMemoryError
volcados grandes (es decir, de las aplicaciones que más necesitaban análisis de almacenamiento dinámico). ) NetBeans Profiler parece usar un algoritmo diferente para indexar referencias que puede ser lento en volcados grandes pero que al menos no consume memoria ilimitada en la herramienta y se bloquea.La mayoría de las veces, en las aplicaciones empresariales, el montón de Java dado es mayor que el tamaño ideal de un máximo de 12 a 16 GB. Me ha resultado difícil hacer que el generador de perfiles de NetBeans funcione directamente en estas grandes aplicaciones de Java.
Pero generalmente esto no es necesario. Puede usar la utilidad jmap que viene con jdk para realizar un volcado de almacenamiento dinámico "en vivo", es decir, jmap volcará el almacenamiento dinámico después de ejecutar GC. Realice alguna operación en la aplicación, espere hasta que se complete la operación, luego realice otro volcado de pila "en vivo". Use herramientas como Eclipse MAT para cargar los heapdumps, ordenar en el histograma, ver qué objetos han aumentado o cuáles son los más altos, esto daría una pista.
Solo hay un problema con este enfoque; Los grandes volcados de almacenamiento dinámico, incluso con la opción en vivo, pueden ser demasiado grandes para transferir a la vuelta de desarrollo, y pueden necesitar una máquina con suficiente memoria / RAM para abrir.
Ahí es donde aparece el histograma de clase. Puede volcar un histograma de clase en vivo con la herramienta jmap. Esto le dará solo el histograma de clase de uso de memoria. Básicamente no tendrá la información para encadenar la referencia. Por ejemplo, puede poner una matriz de caracteres en la parte superior. Y la clase String en algún lugar debajo. Tienes que dibujar la conexión tú mismo.
En lugar de realizar dos volcados de almacenamiento dinámico, tome dos histogramas de clase, como se describe anteriormente; Luego compare los histogramas de clase y vea las clases que están aumentando. Vea si puede relacionar las clases Java con sus clases de aplicación. Esto le dará una muy buena pista. Aquí hay un script de pitones que puede ayudarlo a comparar dos volcados de histograma jmap. histogramparser.py
Finalmente, herramientas como JConolse y VisualVm son esenciales para ver el crecimiento de la memoria con el tiempo y ver si hay una pérdida de memoria. Finalmente, a veces su problema puede no ser una pérdida de memoria, sino un uso elevado de la memoria. Para esto, active el registro de GC; use un GC de compactación más avanzado y nuevo como G1GC; y puede usar herramientas jdk como jstat para ver el comportamiento de GC en vivo
Otras referencias a google para -jhat, jmap, GC completo, asignación enorme, G1GC
fuente
Existen herramientas que deberían ayudarlo a encontrar su fuga, como JProbe, YourKit, AD4J o JRockit Mission Control. El último es el que personalmente conozco mejor. Cualquier buena herramienta debería permitirle profundizar a un nivel en el que pueda identificar fácilmente qué fugas y dónde se asignan los objetos con fugas.
El uso de HashTables, Hashmaps o similar es una de las pocas formas en que puede perder memoria en Java. Si tuviera que encontrar la fuga a mano, imprimiría periódicamente el tamaño de mis HashMaps, y desde allí encontraría el que agrego elementos y me olvidaré de eliminarlos.
fuente
Bueno, siempre existe la solución de baja tecnología de agregar el registro del tamaño de sus mapas cuando los modifica, luego busque en los registros los mapas que crecen más allá de un tamaño razonable.
fuente
NetBeans tiene un generador de perfiles incorporado.
fuente
Realmente necesita usar un generador de perfiles de memoria que rastree las asignaciones. Eche un vistazo a JProfiler : su función "heap walker" es excelente, y tienen integración con todos los IDE principales de Java. No es gratis, pero tampoco es tan costoso ($ 499 por una sola licencia): gastará $ 500 en tiempo luchando rápidamente para encontrar una fuga con herramientas menos sofisticadas.
fuente
Puede averiguarlo midiendo el tamaño de uso de la memoria después de llamar al recolector de basura varias veces:
Si los números de salida eran iguales, no hay pérdida de memoria en su aplicación, pero si vio una diferencia entre los números de uso de memoria (números crecientes), hay una pérdida de memoria en su proyecto. Por ejemplo:
Tenga en cuenta que a veces lleva algún tiempo liberar memoria mediante algunas acciones, como secuencias y sockets. No debe juzgar por las primeras salidas, debe probarlo en un período de tiempo específico.
fuente
Echa un vistazo a este reparto de pantalla sobre la búsqueda de pérdidas de memoria con JProfiler. Es una explicación visual de @Dima Malenko Answer.
Nota: Aunque JProfiler no es un programa gratuito, la versión de prueba puede manejar la situación actual.
fuente
Como la mayoría de nosotros ya usamos Eclipse para escribir código, ¿por qué no usar la herramienta Memory Analyzer Tool (MAT) en Eclipse? Funciona muy bien
El Eclipse MAT es un conjunto de plug-ins para el IDE Eclipse que proporciona herramientas para analizar
heap dumps
desde la aplicación Java y para identificarmemory problems
en la aplicación.Esto ayuda al desarrollador a encontrar pérdidas de memoria con las siguientes características
fuente