Sunday, May 15, 2011

Diagnosing Java.lang.OutOfMemoryError

The heap is one of the foremost components that should be monitored to trace performance issues. Heap pressure is created when the heap usage approaches the maximum heap size permitted. This leads to frequent full garbage collection events. This steals CPU cycles available for processing and the overall response times degrade. Extreme cases can lead to OutOfMemory conditions, which are not recoverable without a JVM restart.

OutOfMemoryError

When I ran my application, it threw the following exceptions:
  • java.lang.OutOfMemoryError: GC overhead limit exceeded[7,9,15]
  • java.lang.OutOfMemoryError: Java heap space
The first message means that, for some reason, the garbage collector is taking an excessive amount of time and recovers very little memory in each run. After I removed the following statement:
  • System.gc();
The 1st message was gone. However, the system threw the 2nd message. So, obviously my heap space issue remains. Here are the steps that I took to investigate it:
  1. Add the following Java Options
    • -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
      • System will generate a gc.log file
    • -XX:+HeapDumpOnOutOfMemoryError
      • System will generate a heap dump file
      • There is an additional HotSpot VM command line option that allows a user to specify a path where the heap dump will be placed
        • -XX:HeapDumpPath=
  2. Analyze the log files:
    • Use regular text editor to examine gc.log file
    • Use Eclipse Memory Analyzer to examine heap dump file (i.e., java_xxx.hprof)
    Note that all command options discussed in this article applied to Hotspot VM.

    JVM Options

    The command line options specify:
    • -XX:+PrintGCDetails
      • prints more details at garbage collection.
    • -XX:+PrintGCTimeStamps
      • prints a time stamp representing the number of seconds since the HotSpot VM was launched until the garbage collection occurred.
    • -Xloggc:gc.log
      • causes information about the heap and garbage collection to be printed at each collection.

    To set Java Options in JDeveloper, do the following:
    1. Right select your project (i.e., ViewController) and bring up the context menu
    2. Select Project Properties...
    3. Select Run/Debug/Profile
    4. Select your Run Configuration (i.e., Default)
    5. Click Edit button
    6. Specify -Xloggc:gc.log -XX:-PrintGCDetails in the Java Options field
    Run your application and reproduce the out-of-memory exception. A log file named gc.log will be generated. I've found mine in the following default location:
    • .../system11.1.1.5.37.60.13/DefaultDomain
    because my web application was deployed to the Integrated WLS[4] and run from DefaultDomain. To understand the format of gc.log, read [5,15] for details.

    However, gc.log file was not really helpful because it simply pointed out there was a heap issue. But, it didn't say where.

    The next step I have taken is running my server with the following flag:

    -XX:+HeapDumpOnOutOfMemoryError

    it generated a java_pid30835.hprof file when my server encountered a heap error.

    Eclipse Memory Analyzer

    The heap dump file (i.e., java_pid30835.hprof) is generated by HPROF—a heap and cpu profiling tool. My heap dump file was generated in binary format. Therefore I need to use Eclpse Memory Analyzer to examine it.

    You can install Eclipse MAT via the Eclipse Update manager . Select "General Purpose Tools " and install "Memory Analyser (Incubation)" and "Memory Analyser (Charts)".
    After installation, double-click your heap dump file and select "Leak Suspects Report".
    Eclipse MAT will show a diagram:
    and problem suspects:
    You can click on the "Details" link to investigate.

    Heap Size Adjustment

    If you observe an OutOfMemoryError in the garbage collection logs, try increasing the Java heap size to 80% of the physical memory you have available for the JVM.   Based on whether the old generation space or the permanent generation space is running out of memory, you adjust the sizes of heap spaces in this way[10]:
    • For old generation space OutOfMemoryErrors
      • increase -Xms and -Xmx
    • For permanent generation OutOfMemoryErrors
      • increase -XX:PermSize and -XX:MaxPermSize

    References
    1. Eclipse Update Manager
    2. Eclipse Memory Analyzer
    3. Java Hotspot VM Options
    4. Integrated WebLogic Server (WLS)
    5. Diagnosing a Garbage Collection problem
    6. Frequently Asked Questions about Garbage Collection
    7. GC Overhead Limit Exceeded
    8. HPROF: A Heap/CPU Profiling Tool in J2SE 5.0
    9. Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning
    10. Java Performance by Charlie Hunt and Binu John
    11. Understanding Garbage Collection
    12. Java HotSpot VM Options
    13. GCViewer (a free open source tool)
    14. Understanding Garbage Collector Output of Hotspot VM
    15. A Case Study of java.lang.OutOfMemoryError: GC overhead limit exceeded
    16. Memory Analyzer Downloads
      • The stand-alone Memory Analyzer is based on Eclipse RCP.

    3 comments:

    Spyros Doulgeridis said...

    Excellent post as usual!!! Thorough, analytic but not boring :)

    Are there any advantages in using
    Eclipse Memory Analyzer instead of Java VisualVM (http://sdoulger.blogspot.com/2011/03/jvisualvm-aka-java-visualvm.html)?

    Stanley Guan said...

    >Eclipse Memory Analyzer vs. Java VisualVM
    I would say there is not any advantages in using MAT instead of Java VisualVM. It's just personal preference (i.e., familiarity with Eclipse).

    Markus Kohler said...

    I tend to disagree (ok I'm biased ;-) ), but the Eclipse Memory Analyzer is still (after VisualVM "copied" some features) much more feature rich and also faster for large heap dumps.

    Regards,
    Markus