Hello everyone, I am a piece of data lying on the Linux disk. Now to send me from the disk to the network card, I need to go through the following steps:
As shown in the figure above: the operating system divides memory into kernel space and user space. First, the application in the user space uses to initiate data read operations, such as those initiated by the JVM
read()System call. At this time, the operating system will do a testContext switch: switch from user space to kernel space.
Then the kernel space informs the disk, and the kernel copies me from the disk to the kernel buffer. This process is done by a hardware called “DMA (direct memory access)”, so it does not need the participation of CPU.
Then the kernel copies me from the kernel buffer to the application buffer, which requires the participation of the CPU.
Finally, the context is switched back to the user space.
The whole process of read operation needsTwo context switches and two copies。
The write operation is similar to the read operation, but the direction is opposite. It still needs two context switches and two copies of data. I may be written to disk or network card.
As you can see from the above process, if you want to send me from disk to NIC, you need a total of 4 context switches and 4 copy operations. I was copied back and forth between kernel space and user space by the operating system, but in fact, I did nothing during this period, nothing changed, it was just copying, so this IO model is a waste of operating system resources, I was copied so many times, and I was tired. And operating system resources are very valuable~
Now mainstream operating systems are usedvirtual memory。 In short, it’s usingVirtual address replaces physical addressIn this way, multiple virtual memories can only want the same physical address, and the space of virtual memory can be much larger than that of physical memory.
If the operating system can map the application buffer in the user space and the kernel buffer in the kernel space to the same physical address, wouldn’t there be a lot less duplication? As shown in the figure below:
So to solve this problem, smart Linux developers have written some new system calls to do it. There are mainly two ways:
- mmap + write
mmap()The system call will first read me from the disk to the kernel buffer using DMA copy, and then through memory mapping,Make the memory address of the user buffer and the kernel read buffer the same, that is to say, the CPU does not need to copy me from the kernel read buffer to the user buffer!
write()When the system calls, the CPU writes me directly from the kernel buffer (equivalent to the user buffer) to the kernel buffer that needs to be sent, such asNetwork send buffer (socket buffer), and then transfer me to the network card driver (or disk) through DMA for sending.
It takes two system calls, four context switches, two DMA copies and one CPU copy to read and write data in MMAP + write mode.
Sendfile is also a system call. In fact, it essentially combines the functions of the above two system calls into one call. The advantage of this is that the operating system only needs two context switches, which reduces the cost of two context switches.
Linux 2.4 kernel optimizes sendfile and provides gather operation, which can remove the last CPU copy in the figure above. The principle is not to copy data, but to send the memory address and offset record of the data in the previous kernel buffer (for example, the case in the figure is read buffer) to the target kernel buffer (for example, the case in the figure is socket buffer), In this way, in the final DMA copy stage, you can directly find the data copy with this pointer.
Zero copy of Linux can really save some operating system resources. Therefore, in order to support zero copy, NiO of Java provides some classes:
Before《Java NIO – Buffer》This article introduces directbytebuffer. There are two main implementations of ByteBuffer: directbytebuffer and heapbytebuffer.
Among them, directbytebuffer allocates memory directly outside the heap, and the bottom layer calls NiO system of the operating system directly through JNI, so the performance will be relatively high. Heapbytebuffer is heap memory, and the data needs to be copied more than once, so the performance is relatively low.
FileChannelJava NiO provides a class for copying files, which can copy files to disk or network.
mapIn fact, the method uses the memory mapping method in the operating system to make an address mapping between the memory in the kernel buffer and the memory in the user buffer.
transferToMethod transfers the contents of the current channel directly to another channel, that is to say, this method will not have the problem of reading and writing from the kernel buffer to the user buffer. The bottom layer is sendfile system call.
transferFromThe method is the same.
File file = new File("test.txt");
Author: official account XY’s technology circle
The above content comes from muke.com
Zero copy is from the perspective of operating system. Because there is no duplicate data between kernel buffers (only kernel buffer has one copy).
Zero copy not only brings less data replication, but also brings other performance advantages, such as less context switching, less CPU cache pseudo sharing and no CPU checksums.
MMAP is suitable for small amount of data reading and writing, sendfile is suitable for large file transmission.
MMAP needs four context switches and three data copies; Sendfile needs three context switches and at least two data copies.
Sendfile can reduce CPU copy by DMA, while MMAP cannot (it must be copied from kernel to socket buffer).
This work adoptsCC agreementReprint must indicate the author and the link of this article