Reputation: 7838
Recently I've been into JVM details and encountered a term Direct Memory. An answer from @Peter Lawrey gripped my attention.
All system calls such as reading and writing sockets and files only use native memory. They can't use the heap.
NIO
, I will just directly use Direct Memory?Upvotes: 3
Views: 547
Reputation: 33727
It is not true that data transfer from and to sockets can only use native (non-heap) memory. It depends entirely on the JVM implementation, and can even vary within the same implementation from time to time.
In fact, it is fairly easy to write JNI functions which use heap memory directly and avoid copies. The JNI API provides methods for zero-copy access to data in the Java heap:
The second one can be very useful when dealing with byte arrays.
These JNI functions may prevent garbage collection from making progress. Often, it is more beneficial to make a copy. This is especially true when making a blocking system call (such as reading from a TCP socket when it is not known for certain that the kernel has buffered data to return). In other cases, it may be possible to process the array incrementally, in smaller pieces, to avoid long stalls and the need for copies.
Due to these challenges, the current implementation in OpenJDK 11 does not attempt zero-copy transfers to and from heap-allocated (non-direct) byte buffers, even in cases where no blocking would occur in the kernel and there would be no impact on garbage collection due to unbounded delays.
Using direct byte buffer with NIO has different problems: These buffers require some sort of finalization. As a result, the garbage collector cannot dispose them as efficiently (and promptly) as other objects. In general, it is prudent to use direct byte buffers only if they are long-lived (for example, allocated along with the channel with which they are used). For temporary buffers, array-backed buffers (or plain arrays) are superior most of the time.
The OpenJDK implementation avoids this problem by associating direct buffers with the current thread, transparently uses them for transfers on channels, and then returns them to the per-thread cache for future use. This way, direct buffers are not constantly allocated and discarded.
The critical section array access functions mentioned above go back to Java 1.2. Whether individual virtual machine and garbage collection implementations still make temporary copies is of course unspecified (the interfaces have been carefully designed in such a way that avoiding copies is not necessary to implement them). In Hotspot in OpenJDK 8, these JNI functions never make a copy, but as explained in Aleksey Shipilёv's article, the impact on garbage collection varies from collector to collector.
Upvotes: 4