How to Fix java.lang.OufOfMemoryError: Direct Buffer Memory

Java allows an application to access non-heap memory by using a direct byte buffer. Many high-performance applications use a direct byte buffer, along with a memory-mapped file for high-speed IO. And, while the ByteBuffer object is small itself, it can hold a large chunk of non-heap memory, which is outside of the Garbage collection scope.  This means the garbage collectors can not reclaim this memory. It is often used to store large data like order or static data cache. Since generally, your program allocates the large buffer e.g. size of 1GB or 2GB, you get "Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory" error, when you try to allocate memory by running the following code

ByteBuffer buffer = ByteBuffer.allocateDirect(SIZE_OF_BUFFER)

java.lang.OutOfMemoryError: Direct buffer memory
    at java.nio.Bits.reserveMemory(Bits.java:632)
    at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:97)
    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)

Now there could be multiple reasons for that e.g. either your system doesn't have enough heap memory, mostly the case when you are requesting a large chunk of memory, or memory hasn't been free from the last usage.

The first case, is pretty straightforward, as your application will fail to start in the first attempt itself, and will not work until you add extra memory or reduce the size of the direct byte buffer.

In the second case, there could be either a memory leak, where your code is holding a reference of ByteBuffer to prevent them from being garbage collected and subsequently your off-heap buffer.


Investigating java.lang.OutOfMemoryError: Direct buffer memory

How to solve java.lang.OutOfMemoryError: Direct buffer memory in Java



                                                                                                                                                                                                                                                                                                                                  This is no different than java.lang.OutOfMemoryError: Java Heap Space, so you can use all the techniques you know e.g. taking heap dump and analyzing them to troubleshoot this error. If you are not using already then, you can use the following JVM options to take heap dump in event of OutOfMemoryError :

-XX:-HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/home/Javin/Desktop/oom_dump.hprof

2) You can use sun.misc.Cleaner class and Java reflection to call clean() method for freeing memory held by direct byte buffer. Since they are garbage collected using a phantom reference and a reference queue, you can still hold the memory allocated to the direct byte buffer, even after discarding all references. 

By explicitly calling the clean() method of Cleaner, you have a better chance of freeing memory and thus avoiding java.lang.OutOfMemoryError: Direct buffer memory. By the way, just remember that this is an internal class and Java doesn't provide any behavior guarantee between different JRE versions

Also you  can not call clean() method of Cleaner directly, like DirectByteBuffer.cleaner().clean() because DirectByteBuffer is a package-private class and not visible outside java.nio package. Only way to explicitly calling clean() is by using reflection e.g.

   Method cleanerMethod = buffer.getClass().getMethod("cleaner");
   cleanerMethod.setAccessible(true);
   Object cleaner = cleanerMethod.invoke(buffer);
   Method cleanMethod = cleaner.getClass().getMethod("clean");
   cleanMethod.setAccessible(true);
   cleanMethod.invoke(cleaner);

3) One more thing, you can do to avoid java.lang.OutOfMemoryError: Direct buffer memory is increasing JVM default memory limit. By default, JVM allows 64MB for direct buffer memory, you can increase it by using JVM option -XX:MaxDirectMemorySize=512m.

That's all on How to fix java.lang.OutOfMemoryError: Direct buffer memory in Java.This is an interesting error but its hard to fix and that's why knowing more about this error and how to avoid it can be the best defence. Let me know if you have faced this issue before or facing it now, I will try to help you here.

Other Java Debugging and Troubleshooting guides for Beginners:
  • How to solve java.lang.NoClassDefFoundError: org/dom4j/DocumentException [solution
  • How to fix java.lang.NoClassDefFoundError: org/apache/xmlbeans/XmlObject Error? [solution]
  • What is difference between ClassNotFoundException and NoClassDefFoundError in Java? [answer]
  • How to solve java.lang.ClassNotFoundException: com.mysql.jdbc.Driver in Java? [answer]
  • 'javac' is not recognized as an internal or external command, operable program, or batch file [solution]
  • How to fix java.lang.unsupportedclassversionerror unsupported major.minor version 61.0 in Java [solution]
  • How to Fix java.lang.classnotfoundexception oracle.jdbc.driver.oracledriver [solution

4 comments:

  1. I don't understand. First, you say that Direct Buffer is not allocated into heap, but before, when an OOM happens, you say "there could be multiple reasons for that e.g. either your system doesn't have enough heap memory, "

    is right ?

    Thanks

    ReplyDelete
  2. I assume the author ment to say the most of the memory is allocated on the native heap but the very small wrapper object is obviously allocated on the JVM heap. So it is realtivly unlikly you get OOM from the JVM heap, but that's possible as an edge case

    ReplyDelete
  3. Thanks, Nice write up,
    According the Sun documentation, the default value of -XX:MaxDirectMemorySize is 0 which means unbounded.
    Refer http://docs.oracle.com/cd/E15289_01/doc.40/e15062/optionxx.htm#BABGCFFB

    ReplyDelete
  4. I tried a online tool http://gceasy.io , it can read gc log.

    ReplyDelete

Feel free to comment, ask questions if you have any doubt.