Pregunta

¿Cuál es la mejor manera de excepciones de depuración java.lang.OutOfMemoryError?

Cuando esto sucede a nuestra aplicación, nuestro servidor de aplicaciones (WebLogic) genera un archivo de volcado del montón. ¿Hay que utilizar el archivo de volcado del montón? ¿Hay que generar un volcado de hilo de Java? ¿Cuál es exactamente la diferencia?


Actualización: ¿Cuál es la mejor manera de generar vertederos de rosca? Es kill -3 (nuestras carreras de aplicaciones en Solaris) la mejor manera de matar a la aplicación y generar un volcado de hilo? ¿Hay una manera de generar el volcado de hilo, pero no mata a la aplicación?

¿Fue útil?

Solución

El análisis y la fijación fuera de la memoria errores en Java es muy simple.

En Java los objetos que ocupan la memoria están relacionados con las algunos otros objetos, formando un árbol gigante. La idea es encontrar los más grandes ramas del árbol, que por lo general apuntar a una situación de pérdida de memoria (en Java, pérdida de memoria no cuando olvida eliminar un objeto, pero cuando se olvida de olvidar el objeto, es decir, a mantener una referencia a ella en alguna parte).

Paso 1. Activar montón vertederos en tiempo de ejecución

Ejecutar el proceso con -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp

(Es seguro tener estas opciones siempre habilitadas. Ajustar el camino, según sea necesario, debe ser modificable por el usuario java)

Paso 2. reproducir el error

Deja que la aplicación se ejecute hasta que se produzca la OutOfMemoryError.

La JVM escribirá automáticamente un archivo como java_pid12345.hprof.

Paso 3. Obtener el vertedero

Copiar java_pid12345.hprof a su PC (será al menos tan grande como su máximo tamaño de la pila, por lo que puede llegar a ser muy grande - gzip si es necesario)

.

Paso 4. Abrir el archivo de volcado de IBM con Montón Analizador Eclipse o de Memory Analyzer

El Montón Analizador le presentará con un árbol de todos los objetos que estaban vivos en el momento del error. Lo más probable es que señalará que directamente en el problema cuando se abre.

IBM HeapAnalyzer

Nota: dar HeapAnalyzer suficiente memoria, ya que tiene que cargar todo el volcado

java -Xmx10g -jar ha456.jar

Paso 5. Identificar las áreas de mayor uso montón

Navegar por el árbol de objetos e identificar objetos que se mantienen en torno innecesariamente.

Nota También puede suceder que todos de los objetos son necesarios, lo que significaría que necesita un montón más grande. Tamaño y sintonizar el montón apropiadamente .

Paso 6. Fijar el código

Asegúrese de que solamente mantener los objetos en torno a que realmente se necesita. Quitar elementos de colecciones de una manera oportuna. Asegúrese de no mantener las referencias a objetos que ya no son necesarios, sólo entonces podrán ser recolección de basura.

Otros consejos

He tenido éxito en el uso de una combinación de Eclipse Memory Analyzer (MAT) y Java Visual VM para analizar vuelcos de almacenamiento dinámico. MAT tiene algunos informes que se pueden ejecutar que le dan una idea general de dónde enfocar sus esfuerzos dentro de su código. VisualVM tiene una mejor interfaz (en mi opinión) para realmente inspeccionar el contenido de los diversos objetos que están interesados ??en examinar. Tiene un filtro donde se puede tener que visualizar todas las instancias de una clase en particular y ver donde están referenciadas y lo que hacen referencia a sí mismos. Ha sido un tiempo desde que he usado cualquiera de las herramientas para ello pueden tener un conjunto de características más cerca ahora. En el momento usando ambos trabajaron bien para mí.

It is generally very difficult to debug OutOfMemoryError problems. I'd recommend using a profiling tool. JProfiler works pretty well. I've used it in the past and it can be very helpful, but I'm sure there are others that are at least as good.

To answer your specific questions:

A heap dump is a complete view of the entire heap, i.e. all objects that have been created with new. If you're running out of memory then this will be rather large. It shows you how many of each type of object you have.

A thread dump shows you the stack for each thread, showing you where in the code each thread is at the time of the dump. Remember that any thread could have caused the JVM to run out of memory but it could be a different thread that actually throws the error. For example, thread 1 allocates a byte array that fills up all available heap space, then thread 2 tries to allocate a 1-byte array and throws an error.

You can also use jmap/jhat to attach to a running Java process. These (family of) tools are really useful if you have to debug a live running application.

You can also leave jmap running as a cron task logging into a file which you can analyse later (It is something which we have found useful to debug a live memory leak)

jmap -histo:live <pid> | head -n <top N things to look for> > <output.log>

Jmap can also be used to generate a heap dump using the -dump option which can be read through the jhat.

See the following link for more details http://www.lshift.net/blog/2006/03/08/java-memory-profiling-with-jmap-and-jhat

Here is another link to bookmark http://java.sun.com/developer/technicalArticles/J2SE/monitoring/

What is the best way to debug java.lang.OutOfMemoryError exceptions?

The OutOfMemoryError describes type of error in the message description. You have to check the description of the error message to handle the exception.

There are various root causes for out of memory exceptions. Refer to oracle documentation page for more details.

java.lang.OutOfMemoryError: Java heap space:

Cause: The detail message Java heap space indicates object could not be allocated in the Java heap.

java.lang.OutOfMemoryError: GC Overhead limit exceeded:

Cause: The detail message "GC overhead limit exceeded" indicates that the garbage collector is running all the time and Java program is making very slow progress

java.lang.OutOfMemoryError: Requested array size exceeds VM limit:

Cause: The detail message "Requested array size exceeds VM limit" indicates that the application (or APIs used by that application) attempted to allocate an array that is larger than the heap size.

java.lang.OutOfMemoryError: Metaspace:

Cause: Java class metadata (the virtual machines internal presentation of Java class) is allocated in native memory (referred to here as metaspace)

java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?:

Cause: The detail message "request size bytes for reason. Out of swap space?" appears to be an OutOfMemoryError exception. However, the Java HotSpot VM code reports this apparent exception when an allocation from the native heap failed and the native heap might be close to exhaustion

java.lang.OutOfMemoryError: Compressed class space

Cause: On 64-bit platforms a pointer to class metadata can be represented by a 32-bit offset (with UseCompressedOops). This is controlled by the command line flag UseCompressedClassPointers (on by default).

If the UseCompressedClassPointers is used, the amount of space available for class metadata is fixed at the amount CompressedClassSpaceSize. If the space needed for UseCompressedClassPointers exceeds CompressedClassSpaceSize, a java.lang.OutOfMemoryError with detail Compressed class space is thrown.

Note: There is more than one kind of class metadata - klass metadata and other metadata. Only klass metadata is stored in the space bounded by CompressedClassSpaceSize. The other metadata is stored in Metaspace.

Should we use the heap dump file? Should we generate a Java thread dump? What exactly is the difference?

Yes. You can use this heap heap dump file to debug the issue using profiling tools like visualvm or mat You can use Thread dump to get further insight about status of threads.

Refer to this SE question to know the differenes:

Difference between javacore, thread dump and heap dump in Websphere

What is the best way to generate thread dumps? Is kill -3 (our app runs on Solaris) the best way to kill the app and generate a thread dump? Is there a way to generate the thread dump but not kill the app?

kill -3 <process_id> generates Thread dump and this command does not kill java process.

It looks like IBM provides a tool for analyzing those heap dumps: http://www.alphaworks.ibm.com/tech/heaproots ; more at http://www-01.ibm.com/support/docview.wss?uid=swg21190476 .

Once you get a tool to look at the heap dump, look at any thread that was in the Running state in the thread stack. Its probably one of those that got the error. Sometimes the heap dump will tell you what thread had the error right at the top.

That should point you in the right direction. Then employ standard debugging techniques (logging, debugger, etc) to hone in on the problem. Use the Runtime class to get the current memory usage and log it as the method in or process in question executes.

I generally use Eclipse Memory Analyzer. It displays the suspected culprits (the objects which are occupying most of the heap dump) and different call hierarchies which is generating those objects. Once that mapping is there we can go back to the code and try to understand if there is any possible memory leak any where in the code path.

However, OOM doesn't always mean that there is a memory leak. It's always possible that the memory needed by an application during the stable state or under load is not available in the hardware/VM. For example, there could be a 32 bit Java process (max memory used ~ 4GB) where as the VM has just 3 GB. In such a case, initially the application may run fine, but OOM may be encountered as and when the memory requirement approaches 3GB.

As mentioned by others, capturing thread dump is not costly, but capturing heap dump is. I have observed that while capturing heap dump application (generally) freezes and only a kill followed by restart helps to recover.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top