Thursday, May 31, 2012

Four flavours of "Out of Memory" in HotSpot JVM

If you are working with Java, I bet you are well aware about OutOfMemoryError. But did you know that there are 4 different conditions when OutOfMemoryError is being thrown in Oracle’s HotSpot JVM? These conditions can be distinguished by message provided by exception.

OutOfMemoryError: Java heap space

This is probably most common case for out of memory error. It indicates that heap space is not large enough to hold object created by application. To be precise, this exception is thrown if, after last full GC cycle, free space in heap is below 2% (can be configured via –XX:GCHeapFreeLimit=p JVM option).
Normally you either have to increase JVM heap size or fix memory leak in your application to remedy this.

OutOfMemoryError: GC overhead limit exceeded

This problem is trickier. It means that GC is spending “too much” time cleaning memory. Portion of free space may be above 1%, but process is spending 50 times more time managing memory than actually executing application code. Threshold can be tweaked via -XX:GCTimeLimit=p JVM option, default is 2% (1/50). Usually if you will increase heap size problem will go away. But this error may also indicate that heap is badly configured, i.e. young space is too small for application.

OutOfMemoryError: PermGen space

As you may know, HotSpot JVM is using special memory space for certain internal structures – permanent space. Despite its name object from permanent space could be collected (name is just a historic artifact). But you may run out of memory in perm space same way as you can in normal heap. Thing which may affect permanent space usage are
  • loading/generating classes and creating with class loaders,
  • reflection,
  • calling String.intern() method.
Permanent space does not count to application heap size. If you need to resize it, use –XX:MaxPermSize=s JVM option.

OutOfMemoryError: Direct buffer memory

All previous types of OOME were indicating that GC failed to free memory for new Java object (i.e. they are thrown as result of GC cycle). This last type of OOME is different. Since Java 1.5, JVM have API to manage memory outside of heap. Out of heap memory is not a subject for garbage collection, but is also limited. Capacity of off heap memory pool is configured via –XX:MaxDirectMemorySize=s JVM option.

My statement about off heap memory not being garbage collected is only partially true. Off heap memory blocks are deallocated in ByteBuffer class finalizer so garbage collection of heap is also driving reclamation of associated off-heap memory.

1 comment:

  1. Nice and concise post.

    Some folks tend to increase heap size blindly, whenever they encounter OOM.

    Now I can point them here so they understand how OOMs can be different. And may indicate different problems, many of which won't be addressed with -Xmx.

    (also IIRC direct memory is a part of NIO which is @since 1.4)