12

Direct memory was introduced since java 1.4. The new I/O (NIO) classes introduced a new way of performing I/O based on channels and buffers. NIO added support for direct ByteBuffers, which can be passed directly to native memory rather than Java heap. Making them significantly faster in some scenarios because they can avoid copying data between Java heap and native heap.

I never understand why do we use direct memory. Can someone help to give an example?

Hearen
  • 7,420
  • 4
  • 53
  • 63
ning morris
  • 257
  • 1
  • 2
  • 8
  • 4
    For performance? – shmosel Oct 11 '18 at 22:16
  • 3
    An example I have is they are great for use with LWJGL, IIRC when you need to pass the vertex data to the GPU you store it in a direct buffer so that you can easily pipe in the data without decoding it from a klass. – vandench Oct 11 '18 at 22:39
  • Isn’t “significantly faster in some scenarios” already reason enough? – Holger Oct 12 '18 at 10:06

2 Answers2

20

I never understand why do we use direct memory. can someone help to give an example?

All system calls such as reading and writing sockets and files only use native memory. They can't use the heap. This means while you can copy to/from native memory from the heap, avoiding this copy can improve efficiency.

We use off-heap/native memory for storing most of our data which has a number of advantages.

  • it can be larger than the heap size.
  • it can be larger than main memory.
  • it can be shared between JVMs. i.e. one copy for multiple JVMs.
  • it can be persisted and retained across restarts of the JVM or even machine.
  • it has little to no impact on GC pause times.
  • depending on usage it can be faster

The reason it is not used more is that it is harder to make it both efficient and work like normal Java objects. For this reason, we have libraries such as Chronicle Map which act as a ConcurrentMap but using off-heap memory, and Chronicle Queue which is a journal, logger and persisted IPC between processes.

user207421
  • 305,947
  • 44
  • 307
  • 483
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
12

The JVM relies on the concept of garbage collection for reclaiming memory that is no longer used. This allows JVM language developers (e.g., Java, Scala, etc) to not have to worry about memory allocation and deallocation. You simply ask for memory, and let the JVM worry about when it will be reclaimed, or garbage collected.

While this is extremely convenient, it comes with the added overhead of a separate thread, consuming CPU and having to go through the JVM heap constantly, reclaiming objects that are not reachable anymore. There's entire books written about the topic, but if you want to read a bit more about JVM garbage collection, there's a ton of references out there, but this one is decent: https://dzone.com/articles/understanding-the-java-memory-model-and-the-garbag

Anyway, if in your app, you know you're going to be doing massive amounts of copying, updating objects and values, you can elect to handle those objects and their memory consumption yourself. So, regardless of how much churn there is in those objects, those objects will never be moved around in the heap, they will never be garbage collected, and thus, won't impact garbage collection in the JVM. There's a bit more detail in this answer: https://stackoverflow.com/a/6091680/236528

From the Official Javadoc:

Direct vs. non-direct buffers

A byte buffer is either direct or non-direct. Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it. That is, it will attempt to avoid copying the buffer's content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system's native I/O operations.

A direct byte buffer may be created by invoking the allocateDirect factory method of this class. The buffers returned by this method typically have somewhat higher allocation and deallocation costs than non-direct buffers. The contents of direct buffers may reside outside of the normal garbage-collected heap, and so their impact upon the memory footprint of an application might not be obvious. It is therefore recommended that direct buffers be allocated primarily for large, long-lived buffers that are subject to the underlying system's native I/O operations. In general it is best to allocate direct buffers only when they yield a measureable gain in program performance.

https://download.java.net/java/early_access/jdk11/docs/api/java.base/java/nio/ByteBuffer.html

mjuarez
  • 16,372
  • 11
  • 56
  • 73
  • 3
    The cited part only says that the direct buffer “may reside outside of the normal garbage-collected heap”, but never claims that this caused a positive impact on the performance of the garbage collector. In fact, it says that they might have “higher allocation and deallocation costs”. Since any serious JVM knows that there are no object references within a `byte[]` array, there is no significant difference between direct and non-direct buffers regarding garbage collection. The differences come into play when native code wants to access the memory, which is an entirely different topic. – Holger Oct 12 '18 at 10:14