Java NIO (a): zero-copy

What is a zero-copy

Wikipedia is so described zero-copy: zero-copy describes CPU does not execute copying data from one storage area to another storage area of ​​the task, which is typically used to reduce the CPU cycles and memory bandwidth when transmitting a document over a network.

Zero-copy to the benefit of us

  • Reduce or even totally avoid unnecessary CPU copy, so that freed CPU to perform other tasks
  • Reduce memory bandwidth usage
  • Typically zero-copy technique is also capable of reducing context switching between operating system kernel space and user space

Zero-copy implementation

The actual realization of zero-copy no real standard, depending on how the operating system to achieve this. Zero copy entirely dependent on the operating system. Operating system support, there; do not support, do not. Java does not rely on itself.

Traditional I / O

In Java, we can read the data from the source through the InputStream data stream in a buffer, then enter them into the OutputStream in. We know that this way IO transmission efficiency is relatively low. So, when using the above-source operating system what happens:
Write pictures described here
1. issue the JVM read () system call.
2. OS context switch to kernel mode (first context switch) and data read to the kernel buffer space. (First Copy: Hardware -> Kernel Buffer)
3. the OS kernel and user space to copy the data to a buffer (second copy: kernel buffer -> user buffer) , read system call then returns. And the system will lead to a return call kernel space to user space context switch (second context switch).
4. JVM code logic processing and transmission write () system call.
5. OS context switch to kernel mode (third context switch) and a buffer copy data from user space to kernel space buffer (Third Copy: user buffer -> kernel buffer) .
6. write system call returns, again resulting in kernel space to user space context switching (Fourth context switch). The kernel space data buffer written Hardware (fourth copy: kernel buffer -> hardware).

总的来说,传统的I/O操作进行了4次用户空间与内核空间的上下文切换,以及4次数据拷贝。显然在这个用例中,从内核空间到用户空间内存的复制是完全不必要的,因为除了将数据转储到不同的buffer之外,我们没有做任何其他的事情。所以,我们能不能直接从hardware读取数据到kernel buffer后,再从kernel buffer写到目标地点不就好了。为了解决这种不必要的数据复制,操作系统出现了零拷贝的概念。注意,不同的操作系统对零拷贝的实现各不相同。在这里我们介绍linux下的零拷贝实现。

通过sendfile实现的零拷贝I/O

Write pictures described here
1. 发出sendfile系统调用,导致用户空间到内核空间的上下文切换(第一次上下文切换)。通过DMA将磁盘文件中的内容拷贝到内核空间缓冲区中(第一次拷贝: hard driver ——> kernel buffer)。
2. 然后再将数据从内核空间缓冲区拷贝到内核中与socket相关的缓冲区中(第二次拷贝: kernel buffer ——> socket buffer)。
3. sendfile系统调用返回,导致内核空间到用户空间的上下文切换(第二次上下文切换)。通过DMA引擎将内核空间socket缓冲区中的数据传递到协议引擎(第三次拷贝: socket buffer ——> protocol engine)。

通过sendfile实现的零拷贝I/O只使用了2次用户空间与内核空间的上下文切换,以及3次数据的拷贝。
你可能会说操作系统仍然需要在内核内存空间中复制数据(kernel buffer —>socket buffer)。 是的,但从操作系统的角度来看,这已经是零拷贝,因为没有数据从内核空间复制到用户空间。 内核需要复制的原因是因为通用硬件DMA访问需要连续的内存空间(因此需要缓冲区)。 但是,如果硬件支持scatter-and-gather,这是可以避免的。

带有DMA收集拷贝功能的sendfile实现的I/O

Write pictures described here
1. 发出sendfile系统调用,导致用户空间到内核空间的上下文切换(第一次上下文切换)。通过DMA引擎将磁盘文件中的内容拷贝到内核空间缓冲区中(第一次拷贝: hard drive ——> kernel buffer)。
2. 没有数据拷贝到socket缓冲区。取而代之的是只有相应的描述符信息会被拷贝到相应的socket缓冲区当中。该描述符包含了两方面的信息:a)kernel buffer的内存地址;b)kernel buffer的偏移量。
3. sendfile系统调用返回,导致内核空间到用户空间的上下文切换(第二次上下文切换)。DMA gather copy根据socket缓冲区中描述符提供的位置和偏移量信息直接将内核空间缓冲区中的数据拷贝到协议引擎上(第二次拷贝: kernel buffer ——> protocol engine),这样就避免了最后一次CPU数据拷贝。

带有DMA收集拷贝功能的sendfile实现的I/O只使用了2次用户空间与内核空间的上下文切换,以及2次数据的拷贝,而且这2次的数据拷贝都是非CPU拷贝。这样一来我们就实现了最理想的零拷贝I/O传输了,不需要任何一次的CPU拷贝,以及最少的上下文切换。

许多Web服务器都支持零拷贝,如Tomcat和Apache。 例如Apache的相关文档可以在这里找到,但默认情况下关闭。
注意:Java的NIO通过transferTo()提供了这个功能。

传统I/O用户空间缓冲区中存有数据,因此应用程序能够对此数据进行修改等操作;而sendfile零拷贝消除了所有内核空间缓冲区与用户空间缓冲区之间的数据拷贝过程,因此sendfile零拷贝I/O的实现是完成在内核空间中完成的,这对于应用程序来说就无法对数据进行操作了。为了解决这个问题,Linux提供了mmap零拷贝来实现我们的需求。

通过mmap实现的零拷贝I/O

mmap(内存映射)是一个比sendfile昂贵但优于传统I/O的方法。
Write pictures described here
1. 发出mmap系统调用,导致用户空间到内核空间的上下文切换(第一次上下文切换)。通过DMA引擎将磁盘文件中的内容拷贝到内核空间缓冲区中(第一次拷贝: hard drive ——> kernel buffer)。
2. mmap系统调用返回,导致内核空间到用户空间的上下文切换(第二次上下文切换)。接着用户空间和内核空间共享这个缓冲区,而不需要将数据从内核空间拷贝到用户空间。因为用户空间和内核空间共享了这个缓冲区数据,所以用户空间就可以像在操作自己缓冲区中数据一般操作这个由内核空间共享的缓冲区数据。
3. 发出write系统调用,导致用户空间到内核空间的上下文切换(第三次上下文切换)。将数据从内核空间缓冲区拷贝到内核空间socket相关联的缓冲区(第二次拷贝: kernel buffer ——> socket buffer)。
4. write系统调用返回,导致内核空间到用户空间的上下文切换(第四次上下文切换)。通过DMA引擎将内核空间socket缓冲区中的数据传递到协议引擎(第三次拷贝: socket buffer ——> protocol engine)

通过mmap实现的零拷贝I/O进行了4次用户空间与内核空间的上下文切换,以及3次数据拷贝。其中3次数据拷贝中包括了2次DMA拷贝和1次CPU拷贝。明显,它与传统I/O相比仅仅少了1次内核空间缓冲区和用户空间缓冲区之间的CPU拷贝。这样的好处是,我们可以将整个文件或者整个文件的一部分映射到内存当中,用户直接对内存中对文件进行操作,然后是由操作系统来进行相关的页面请求并将内存的修改写入到文件当中。我们的应用程序只需要处理内存的数据,这样可以实现非常迅速的I/O操作。

说了这么多,那么Java NIO中对零拷贝的使用有哪些呢?

NIO DirectByteBuffer

Java NIO ByteBuffer for the introduction of a buffer passage. There are three main ByteBuffer achieve:

HeapByteBuffer

Used when calling ByteBuffer.allocate (). It is called the heap, because it is stored in the JVM heap space, so you can get all the benefits, such as GC support and cache optimization. However, it is not a page-aligned, which means that if you need to talk through the JNI native code, JVM will have to copy into the buffer space aligned.

DirectByteBuffer

Used when calling ByteBuffer.allocateDirect (). JVM uses malloc () to allocate memory space in the space outside the stack. Because it is not managed by the JVM, so your memory is page-aligned, not GC influence, which makes it a perfect choice for handling native code. However, you want to C programmers, to manage this memory, you must own allocate and free memory to prevent memory leaks.

MappedByteBuffer

Used when calling FileChannel.map (). And DirectByteBuffer similar, which is the JVM heap external circumstances. It basically functions as a packaging OS mmap () system call, the operating code directly to physical memory mapping data.

to sum up

Zero copy is an implementation of the underlying operating system, we network programming, using this feature the operating system, it can greatly improve the efficiency of data transmission. This is also the way network programming framework will be adopted, a good understanding of zero-copy, help us to further study the underlying principles of the Internet and other communication framework of Netty.

Published 165 original articles · won praise 22 · views 40000 +

Guess you like

Origin blog.csdn.net/XiaoHanZuoFengZhou/article/details/103993665