JVM automatically perform Garbage Collection (GC), when it detects its about to reach the heap size limits. But the GC can only clean the objects which are eligible for GC. If the JVM can't allocate required memory even after GC, JVM will crash with "Exception in thread "main" java.lang.OutOfMemoryError: Java heap space"
If your Java application in production crashes due to some issue like this, you cant just ignore the incident, and restart your application. You have to analyze the what cause the JVM crash, and take the necessary actions to avoid it happening again. This is where the JVM heap dump comes in to the play.
JVM heap dumps are by default disabled, you have to enable heap dumps explicitly by providing following JVM option, -XX:+HeapDumpOnOutOfMemoryError
The below sample code, tries to create a multiple, large arrays of chars, and keep the references in list. Which cause those large arrays ineligible for garbage collection.
package com.test; import java.util.ArrayList; import java.util.List; public class TestClass { public static void main(String[] args) { List<Object> list = new ArrayList<Object>(); for (int i = 0; i < 1000; i++) { list.add(new char[1000000]); } } }
If you run the above code with following command lines,
1. java -XX:+HeapDumpOnOutOfMemoryError -Xms10m -Xmx3g com.test.TestClass
Result: Program runs and exit without any error. The heap size starts from 10MB and then grows as needed. Above needs memory less than 3GB. So, it completes without any error.
2. java -XX:+HeapDumpOnOutOfMemoryError -Xms10m -Xmx1g com.test.TestClass
Result: JVM crashes with OOM.
If we change the above code a bit to remove the char array from the list, after adding to the list. what would be the result
package com.test; import java.util.ArrayList; import java.util.List; public class TestClass { public static void main(String[] args) { List<Object> list = new ArrayList<Object>(); for (int i = 0; i < 1000; i++) { list.add(new char[1000000]); list.remove(0); } } }
3. java -XX:+HeapDumpOnOutOfMemoryError -Xms10m -Xmx10m com.test.TestClass
Result: This code runs without any issue even with a heap of 10MBs.
NOTE:
1. There is no impact to your application if you enable the heap dump in the JVM. So, it is better to always enable -XX:+HeapDumpOnOutOfMemoryError in your applications
2. You can create a heap dump of a running Java application with the use of jmap. jmap come with the JDK. Creating a heap dump of a running application cause the application to halt everything for a while. So, not recommended to use in production system. (unless there is a extreme situation)
eg: jmap -dump:format=b,file=test-dump.hprof [PID]
3. Above sample codes are just for understanding the concept.
[1] https://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/garbage_collect.html
Edit:
Following are few other important flags that could be useful in generating heap dumps;
-XX:HeapDumpPath=/tmp/heaps
-XX:OnOutOfMemoryError="kill -9 %p" : with this you can execute command at the JVM exit
-XX:+ExitOnOutOfMemoryError : When you enable this option, the JVM exits on the first occurrence of an out-of-memory error. It can be used if you prefer restarting an instance of the JVM rather than handling out of memory errors [2].
-XX:+CrashOnOutOfMemoryError : CrashOnOutOfMemoryError - If this option is enabled, when an out-of-memory error occurs, the JVM crashes and produces text and binary crash files (if core files are enabled) [2].
[2] http://www.oracle.com/technetwork/java/javase/8u92-relnotes-2949471.html