A long article takes you to easily handle NiO and zero copy in Linux, JDK and netty!

Java program ape 2022-06-24 06:05:19 阅读数:457

longarticletakeseasilyhandle

One 、 First understand kernel space and user space

Linux According to the privilege level , The running space of process is divided into kernel space and user space , Corresponding to the figure below , CPU Privilege levels are divided into 4 individual ,Linux Use Ring 0 and Ring 3.

  • Kernel space (Ring 0) With the highest authority , Direct access to all resources ,;
  • User space (Ring 3) Only limited resources can be accessed , Can not directly access the memory and other hardware devices , Must pass system call Get stuck in the kernel , To access these privileged resources .

above Ring The diagram can be simplified to :

The kernel is essentially a kind of software —— Control the hardware resources of the computer , And provide the environment for the upper application to run . User mode is the activity space of the upper application , The execution of the application must depend on the resources provided by the kernel , Include CPU resources 、 Storage resources 、I/O Resources, etc . In order to enable the upper application to access these resources , The kernel must provide an access interface for the upper application : namely system call .

Java Learning note sharing address :13.BIO,NIO,AIO,Nett Learning notes

system call Is the smallest functional unit of the operating system , By providing some basic function interfaces for the application program to call to schedule the resources managed by the kernel space

The system call can be compared to a Chinese character “ stroke ”, And one “ Chinese characters ” It represents an upper application . therefore , Sometimes if you want to realize a complete Chinese character ( Allocate memory space to a variable ), You have to call a lot of system calls ( stroke ). If from the implementer ( The programmer ) From the perspective of , This is bound to increase the burden on programmers , A good programming method is : Pay attention to the business logic operation of the upper layer , And try to avoid the underlying complex implementation details . Library function It is an effective method to free programmers from complex details . It implements encapsulation of system calls , Present a simple business logic interface to the user , User friendly , Look at it this way , Library functions are like those that make up Chinese characters “ Side by side ”.

Shell It's a special application , Commonly known as the command line , Essentially a command interpreter , It's down to system call , All kinds of applications , Usually acting as a kind of “ glue ” Role , To connect the widgets , Let different programs work together with a clear interface , So as to enhance the functions of various programs . Usually just a few lines Shell Script can achieve a very big function , And that's why Shell Statements usually encapsulate system calls .

Two 、 Loss of switching between user mode and kernel mode

When the program is switched from user mode to kernel mode , Then the thread in user mode needs to save the current data and the running instructions , It is convenient to continue execution when returning to the user status , There are many other things that need to be done , for example CPU Registers need to be saved and loaded , The system scheduler's code needs to be executed , TLB The instance needs to be reloaded , CPU Of pipeline Need to brush off .

TLB

A page table It's usually big , And stored in memory , So the processor introduces MMU after , Read instruction 、 Data needs to access memory twice : First, get the physical address by querying the page table , Then access the physical address to read instructions 、 data . To reduce because MMU Resulting in processor performance degradation , Introduced TLB,TLB yes Translation Lookaside Buffer For short , It can be translated into “ Address translation backup buffer ”, It can also be referred to as “ Watch it ”. In short ,TLB It's the page table Cache, It stores the page table items that are most likely to be accessed at present , Its content is a copy of a partial page table entry . Only in TLB When the address translation task cannot be completed , To query the page table in memory , This reduces the processor performance degradation caused by page table queries .

A page table

It's a special data structure , Put it in the page table area of system space , Store the corresponding relationship between logical page and physical page frame . Each process has its own page table ,PCB There is a pointer in the table to the page table .

MMU

Memory management unit ( English :memory management unit, Abbreviation for MMU), Sometimes called paging memory management unit ( English :paged memory management unit, Abbreviation for PMMU). It's a kind of CPU (CPU) Computer hardware for memory access requests for .

TLB The item in consists of two parts : Identification and data . What is stored in the logo is a part of the virtual address , The physical page number is stored in the data part 、 Store protection information and other auxiliary information . Virtual address and TLB There are three ways to map items in : Full association mode 、 Direct mapping 、 Group association method .OR1200 The processor implements direct mapping , So this book only introduces the direct mapping method . Direct mapping means that each virtual address can only be mapped to TLB The only entry in the . Suppose the memory page size is 8KB,TLB There is 64 term , When direct mapping is used TLB The transformation principle is shown in the figure :

CPU Of Pipeline

stay CPU Zhongyou 5—6 An instruction processing pipeline is composed of three circuit units with different functions , Then divide an instruction into 5—6 After that, these circuit units perform the following steps respectively , This can be achieved in a CPU The clock cycle completes an instruction , So improve CPU Operation speed of .

3、 ... and 、 The basic process of file transfer

1、DMA Previous file copy process

DMA Before the traditional IO Copy the sequence diagram :

Use I/O Interrupt mode data reading steps :

  1. User process to CPU launch read System call to read data , Switch from user state to kernel state , And then keep blocking and waiting for the data to return ;
  2. CPU After receiving the instruction, it initiates I/O request , Put the disk data into the disk controller buffer first ;
  3. When the data is ready , Disk to CPU launch I/O interrupt ;
  4. CPU received I/O After interruption, copy the data in the disk buffer to the kernel buffer , Then copy from kernel buffer to user buffer ;
  5. The user process switches from kernel state to user state , Unblock , And then wait CPU The next execution clock of .

2、DMA Then the file reading process

2.1 DMA Copy and CPU The difference between replication

CPU Copy

stay DMA Before technology , Between the application and the disk I/O Operation is through CPU Of interruptions completed . Every time a user process reads disk data , Need to be CPU Interrupt reading data into the register , Then launch I/O The request waits for the data to be read and copied , Then write it down somewhere else , Every time the I/O Interruptions all lead to CPU Context switch of .

DMA Copy

DMA(Direct Memory Access, Direct memory access ) , stay DMA Previous CPU Copy , need CPU Read data into register ( Different from register ), Then write it down somewhere else , In the process ,CPU Be occupied , and DMA Does not affect when copying CPU To run other tasks . Specific process :CPU Yes DMA Controller initialization , towards I/O Interface sends operation commands ,I/O Interface proposal DMA request .DMA The controller is right DMA Request discrimination priority and shielding , Make a bus request to the bus arbitration logic . When CPU After executing the current bus cycle, the bus control right can be released . here , Bus arbitration logic outputs bus response , Express DMA Has responded to , adopt DMA Controller notification I/O Interface start DMA transmission .

2.2 DMA Copy the process

The system reads data from the disk ,DMA Copy Into the kernel page cache ,

And then through CPU Copy Read the cache space for the user ,

And then through CPU Write in Socket Buffer zone ,

Finally through DMA Copy transmission into the network .

2.3 DMA Copy the diagram

It can be seen from the picture that :DMA Copy , Four data copies required , Four context switches , Even if DMA To handle communication with hardware ,CPU Still need to process two copies of data , meanwhile , In the user mode and the kernel mode, there are many context switches , No doubt it's aggravating CPU burden .

2.4 DMA Under the IO Copy the sequence diagram

CPU From heavy I/O Release during operation , The flow of data reading operation is as follows :

  1. User process to CPU launch read System call to read data , Switch from user state to kernel state , And then keep blocking and waiting for the data to return ;
  2. CPU After receiving the instruction, I'll reply to DMA The disk controller initiates the scheduling instruction ;
  3. DMA Disk controller initiates... To disk I/O request , Put the disk data into the disk controller buffer first ,CPU Do not participate in the whole process ;
  4. After reading the data ,DMA The disk controller will receive a disk notification , Copy data from disk controller buffer to kernel buffer ;
  5. DMA Disk controller to CPU Signal that the data has been read , from CPU Responsible for copying data from kernel buffer to user buffer ;
  6. The user process switches from kernel state to user state , Unblock , And then wait CPU The next execution clock of .

Four 、 Zero copy process

Zero copy , Mainly refers to CPU Copy

1、 The principle of zero copy

Linux Zero copy technology mainly includes 3 There is a way to achieve it : User status is direct I/O、 Reduce the number of data copies as well as Copy on write technology .

1.1 User status is direct I/O

Applications have direct access to hardware storage , The operating system kernel is just auxiliary data transmission . This way, There is still context switching between user space and kernel space , The data on the hardware is copied directly to the user space , Without going through kernel space . therefore , direct I/O There is no copy of data between kernel space buffer and user space buffer .

1.2 Reduce the number of data copies

In the process of data transmission , Avoid data between user space buffer and system kernel space buffer CPU Copy , And data in the system kernel space CPU Copy , This is also the implementation idea of the current mainstream zero copy technology .

1.3 Copy on write technology

Copy on write refers to when multiple processes share the same piece of data , If one of the processes needs to modify this data , Then copy it to your own process address space , If it's just a data read operation, you don't need to copy it .

2 、 User status is direct I/O

User status is direct I/O Make the application process or run in user mode (user space) Direct access to hardware devices , Data is transferred directly across the kernel and written directly from the user state address space to the disk , In the process of data transmission, the kernel performs the necessary virtual storage configuration , Not involved in any other work , This way you can bypass the kernel directly , Greatly improved performance . For some applications , for example : database . They prefer their own caching mechanism , This can provide a better buffer mechanism and improve the read-write performance of the database .

2.1 direct I/O Icon

2.2 direct I/O Design and implementation

To perform direct... In a block device I/O, The process must set the file access mode to... When opening the file O_DIRECT, This is tantamount to telling the operating system that the process will use read() perhaps write() When the system call reads and writes files, it uses direct I/O The way , The transmitted data does not pass through the operating system kernel cache space . Use direct I/O When reading and writing data, you must pay attention to Buffer alignment ( buffer alignment ) And the size of the buffer , The corresponding read() as well as write() The second and third parameters of the system call . The alignment mentioned here refers to the alignment of file system block size , The size of the buffer must also be an integer multiple of the block size .

2.3 direct I/O shortcoming

  1. This method can only be applied to applications that do not need kernel buffer processing , These applications usually have their own data caching mechanism in the process address space , Called a self Caching Application , For example, database management system is a representative .
  2. This method operates the disk directly I/O, because CPU And disk I/O Implementation time gap between , It wastes resources , Solving this problem requires further I/O Use a combination of .

3、 Reduce the number of data copies mmap

One way to do zero copy is to use mmap + write Replace the original read + write The way , Less 1 Time CPU Copy operation .mmap yes Linux Provides a memory mapping file method , That is, a virtual address in the address space of a process is mapped to the disk file address ,mmap + write The pseudo-code is as follows :

tmp_buf = mmap(file_fd, len);
write(socket_fd, tmp_buf, len);

Use mmap The purpose is to read the buffer in the kernel (read buffer) Address and user space buffer (user buffer) mapping , So as to realize the sharing of kernel buffer and application memory , No need to read data from the kernel buffer (read buffer) Copy to user buffer (user buffer) The process of , However, the kernel read buffer (read buffer) Still need to write data to kernel buffer (socket buffer).

3.1 mmap Reduce data copy flow chart

3.2 mmap+write Copy process

be based on mmap + write Zero copy of system call , The whole copy process happens 4 Subcontext switch ,1 Time CPU Copy and 2 Time DMA Copy , The process of reading and writing data by user program is as follows :

  1. The user process passes through mmap() Function to kernel (kernel) Make a system call , Context From user mode (user space) Switch to kernel state (kernel space);
  2. The read buffer in the kernel space of the user process (read buffer) Cache associated with user space (user buffer) Memory address mapping ;
  3. CPU utilize DMA The controller copies data from main memory or hard disk to kernel space (kernel space) Read buffer for (read buffer);
  4. Context From the kernel state (kernel space) Switch back to user mode (user space),mmap System call execution returns ;
  5. The user process passes through write() Function to kernel (kernel) Make a system call , Context From user mode (user space) Switch to kernel state (kernel space);
  6. CPU Will read buffer (read buffer) The network buffer to which the data in is copied (socket buffer) ;
  7. CPU utilize DMA The controller takes data from the network buffer (socket buffer) Copy to network card for data transmission ;
  8. Context From the kernel state (kernel space) Switch back to user mode (user space) ,write System call execution returns ;

3.3 mmap+write Copy defects :

mmap The main use is to improve I/O performance , Especially for large documents . For small files , Memory mapping file will lead to waste of debris space , Because memory mapping always aligns page boundaries , The smallest unit is 4 KB, One 5 KB The file will be mapped to take 8 KB Memory , It's a waste 3 KB Memory .

in addition mmap There is a trap , When using mmap When mapping a file , If this file is intercepted by another process , that write The system call will be SIGBUS Signal termination ,SIGBUS By default, the process is killed and a coredump, If the server is terminated in this way, the loss may not be small .

To solve this problem, we usually use the lease lock of the file : First apply for a rental lock for the file , When other processes want to truncate this file , The kernel will send a real-time RT_SIGNAL_LEASE The signal , Tell the current process that a process is trying to destroy the file , such write In being SIGBUS Before killing , Will be interrupted , Returns the number of bytes that have been written , And set up errno by success.

The usual way is to mmap Lock before , Unlock after operation .

4、 Reduce the number of data copies sendfile

sendfile System call in Linux Kernel version 2.1 Introduced in , The purpose is to simplify the data transmission process between two channels through the network .sendfile Introduction of system call , Not only is it reduced CPU The number of copies , It also reduces the number of context switches , Its pseudo code is as follows :

sendfile(socket_fd, file_fd, len);

adopt sendfile system call , Data can be done directly inside kernel space I/O transmission , In this way, the back and forth copy of data between user space and kernel space is eliminated . And mmap The difference in memory mapping is ,sendfile in call I/O Data is completely invisible to user space . in other words , This is a complete data transmission process .

4.1 sendfile Copy diagram

4.2 sendfile Copy process

be based on sendfile Zero copy of system call , The whole copy process happens 2 Subcontext switch ,1 Time CPU Copy and 2 Time DMA Copy , The process of reading and writing data by user program is as follows :

  1. The user process passes through sendfile() Function to kernel (kernel) Make a system call , Context from user state (user space) Switch to kernel state (kernel space).
  2. CPU utilize DMA The controller copies data from main memory or hard disk to kernel space (kernel space) Read buffer for (read buffer).
  3. CPU Will read buffer (read buffer) The network buffer to which the data in is copied (socket buffer).
  4. CPU utilize DMA The controller takes data from the network buffer (socket buffer) Copy to network card for data transmission .
  5. Context from kernel state (kernel space) Switch back to user mode (user space),sendfile System call execution returns .

Compared with mmap How memory is mapped ,sendfile Less 2 Subcontext switch , But there is still 1 Time CPU Copy operation .sendfile The problem is that the user program can't modify the data , And just completed a data transmission process .

4.3 sendfile Copy disadvantages

Only for applications that don't need user state processing .

5、 Reduce the number of data copies sendfile + DMA

routine sendfile There is also a kernel copy operation , Can you also remove this copy ?

There are , such DMA Auxiliary sendfile.

Linux 2.4 Version of the kernel for sendfile System call to modify , by DMA Copy introduces gather operation . It will take kernel space (kernel space) The reading of buffer (read buffer) Corresponding Data description information ( Memory address 、 Address offset ) Record the corresponding Network buffer ( (socket buffer) in , from DMA According to the memory address 、 The address offset removes data from the read buffer in bulk (read buffer) Copy to the NIC device , This saves the kernel space that's left 1 Time CPU Copy operation ,sendfile The pseudo-code is as follows :

Copysendfile(socket_fd, file_fd, len);

With the support of hardware ,sendfile Copy mode no longer copies data from kernel buffer to socket buffer , Instead, it's just a copy of the buffer file descriptor and data length , such DMA The engine directly uses gather Operation to package and send the data in the page cache to the network , The essence is similar to the idea of virtual memory mapping .

5.1 sendfile + DMA Sketch Map

5.2 sendfile+DMA Copy process

be based on sendfile + DMA gather copy Zero copy of system call , The whole copy process happens 2 Subcontext switch 、0 Time CPU Copy and 2 Time DMA Copy , The process of reading and writing data by user program is as follows :

  1. The user process passes through sendfile() Function to kernel (kernel) Make a system call , Context from user state (user space) Switch to kernel state (kernel space).
  2. CPU utilize DMA The controller copies data from main memory or hard disk to kernel space (kernel space) Read buffer for (read buffer).
  3. CPU Put the read buffer (read buffer) File descriptor for (file descriptor) And data length to the network buffer (socket buffer).
  4. Based on the copied file descriptor (file descriptor) And data length ,CPU utilize DMA Controller gather/scatter The operation directly batches the data from the kernel's read buffer (read buffer) Copy to network card for data transmission .
  5. Context from kernel state (kernel space) Switch back to user mode (user space),sendfile System call execution returns .

5.3 sendfile+DMA Copy disadvantages

sendfile + DMA gather copy Copy mode also has the problem that the user program can't modify the data , And it needs hardware support , It only applies to copying data from a file to socket The transmission process on the socket .

6、 Reduce the number of data copies splice

sendfile Only for copying data from a file to socket On the socket , At the same time, it needs hardware support , This also limits the scope of its use .Linux stay 2.6.17 Version to introduce splice system call , Not only does it not require hardware support , It also realizes zero copy of data between two file descriptors .splice The pseudo-code is as follows :

Copysplice(fd_in, off_in, fd_out, off_out, len, flags);

splice System calls can be made in the read buffer of kernel space (read buffer) And network buffers (socket buffer) Build a pipeline between (pipeline), So as to avoid the conflict between the two CPU Copy operation .

6.1 splice Flow diagram

6.2 splice technological process

be based on splice Zero copy of system call , The whole copy process happens 2 Subcontext switch ,0 Time CPU Copy and 2 Time DMA Copy , The process of reading and writing data by user program is as follows :

  1. The user process passes through splice() Function to kernel (kernel) Make a system call , Context from user state (user space) Switch to kernel state (kernel space);
  2. CPU utilize DMA The controller copies data from main memory or hard disk to kernel space (kernel space) Read buffer for (read buffer);
  3. CPU Read buffer in kernel space (read buffer) And network buffers (socket buffer) Build a pipeline between (pipeline);
  4. CPU utilize DMA The controller takes data from the network buffer (socket buffer) Copy to network card for data transmission ;
  5. Context from kernel state (kernel space) Switch back to user mode (user space),splice System call execution returns .

splice The copy mode also has the problem that the user program can't modify the data . besides , It has been used. Linux The pipeline buffer mechanism , It can be used to transfer data in any two file descriptors , But one of its two file descriptor parameters must be a pipeline device .

7、 When writing copy

In some cases , Kernel buffers can be shared by multiple processes , If a process wants this share to work write operation , because write No lock operation is provided , Then it will destroy the data in the share , The introduction of copy on write is Linux To protect data .

Copy on write refers to when multiple processes share the same piece of data , If one of the processes needs to modify this data , Then you need to copy it to your own process address space . This does not affect the operation of this data by other processes , Each process is copied only when it needs to be modified , So it's called copy on write . This method can reduce the system overhead to some extent , If a process never changes the data it accesses , Then you never need to copy .

shortcoming :

need MMU Support for ,MMU You need to know which pages in the process address space are read-only , When you need to write data to these pages , Send an exception to the operating system kernel , The kernel allocates new storage space for writing requirements .

8、 Buffer sharing

Buffer sharing completely rewrites the traditional I/O operation , Conventional Linux I/O The interface supports data in Application address space and Between operating system kernels In exchange for , This exchange operation causes all data to be copied .

If the fbufs This method , need What is exchanged is a buffer containing data , This eliminates redundant copy operations . The application will fbuf Passed to the operating system kernel , This will reduce the traditional write The cost of copying data from system calls .

The same application passes fbuf To receive data , This can also reduce the traditional read The cost of copying data from system calls .

fbuf The idea is that every Processes maintain a buffer pool , This buffer pool can be mapped to user space at the same time (user space) And kernel state (kernel space), The kernel and the user share this buffer pool , This avoids a series of copy operations .

shortcoming :

The difficulty with buffer sharing is that managing the shared buffer pool requires applications 、 Close collaboration between network software and device drivers , And how to rewrite API It's still in the experimental stage, not mature .

9、Linux Zero copy comparison

Whether it's tradition I/O Copy or zero copy ,2 Time DMA Copy It's indispensable , Because twice DMA It all depends on hardware . The following from CPU Number of copies 、DMA Copy times and system calls to summarize the above I/O The difference in copy mode .

5、 ... and 、Netty Zero copy in

1、JDK Zero copy - MappedByteBuffer

MappedByteBuffer yes NIO Memory-based mapping (mmap) This kind of zero copy mode provides an implementation , It is inherited from ByteBuffer.FileChannel Defined a map() Method , It can take a file from position The position begins size The size of the area is mapped to the memory image file . Abstract method map() Method in FileChannel The definitions in are as follows :

Copypublic abstract MappedByteBuffer map(MapMode mode, long position, long size)
throws IOException;
  • mode: Limit memory mapping area (MappedByteBuffer) Access patterns to memory image files , Including only readable (READ_ONLY)、 Can read but write (READ_WRITE) And copy on write (PRIVATE) Three models .
  • position: The starting address of the file map , Corresponding memory mapping area (MappedByteBuffer) The first address .
  • size: The byte length of the file map , from position The number of bytes after that , Corresponding memory mapping area (MappedByteBuffer) Size .

MappedByteBuffer comparison ByteBuffer Added fore()、load() and isLoad() Three important ways :

  • fore(): For being in READ_WRITE Buffer in mode , Force the changes to the contents of the buffer to refresh to the local file .
  • load(): Load the contents of the buffer into physical memory , And return a reference to this buffer .
  • isLoaded(): If the contents of the buffer are in physical memory , Then return to true, Otherwise return to false.

Here's a use MappedByteBuffer Examples of reading and writing files :

Copyprivate final static String CONTENT = " I want to test zero copy write data ";
private final static String FILE_NAME = "/Users/yangyue/Downloads/1.txt";
public static void main(String[] args) {
Path path = Paths.get(FILE_NAME);
byte[] bytes = CONTENT.getBytes(Charset.forName("UTF-8"));
try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ,
StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
MappedByteBuffer mappedByteBuffer = fileChannel.map(READ_WRITE, 0, bytes.length);
if (mappedByteBuffer != null) {
mappedByteBuffer.put(bytes);
mappedByteBuffer.force();
}
} catch (IOException e) {
e.printStackTrace();
}
}

Open the file channel fileChannel And provide read access 、 Write permission and data clear permission , adopt fileChannel Mapped to a writable memory buffer mappedByteBuffer, Write the target data to mappedByteBuffer, adopt force() Method to force the contents of the buffer changes to the local file .

Test read file :

Copypublic static void read(){
Path path = Paths.get(FILE_NAME);
int length = CONTENT.getBytes(Charset.forName("UTF-8")).length;
try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)) {
MappedByteBuffer mappedByteBuffer = fileChannel.map(READ_ONLY, 0, length);
if (mappedByteBuffer != null) {
byte[] bytes = new byte[length];
mappedByteBuffer.get(bytes);
String content = new String(bytes, StandardCharsets.UTF_8);
System.out.println(content);
}
} catch (IOException e) {
e.printStackTrace();
}
}

map() The method is java.nio.channels.FileChannel Abstract method of , From subclass sun.nio.ch.FileChannelImpl.java Realization , Here's the core code related to memory mapping :

Copypublic MappedByteBuffer map(MapMode var1, long var2, long var4) throws IOException {
if (var4 == 0L) {
var7 = 0L;
FileDescriptor var38 = new FileDescriptor();
if (this.writable && var6 != 0) {
var17 = Util.newMappedByteBuffer(0, 0L, var38, (Runnable)null);
return var17;
}
var17 = Util.newMappedByteBufferR(0, 0L, var38, (Runnable)null);
return var17;
}
var12 = (int)(var2 % allocationGranularity);
long var36 = var2 - (long)var12;
var10 = var4 + (long)var12;
try {
var7 = this.map0(var6, var36, var10);
} catch (OutOfMemoryError var31) {
System.gc();
try {
Thread.sleep(100L);
} catch (InterruptedException var30) {
Thread.currentThread().interrupt();
}
try {
var7 = this.map0(var6, var36, var10);
} catch (OutOfMemoryError var29) {
throw new IOException("Map failed", var29);
}
}
FileDescriptor var13;
try {
var13 = this.nd.duplicateForMapping(this.fd);
} catch (IOException var28) {
unmap0(var7, var10);
throw var28;
}
assert IOStatus.checkAll(var7);
assert var7 % allocationGranularity == 0L;
int var35 = (int)var4;
FileChannelImpl.Unmapper var15 = new FileChannelImpl.Unmapper(var7, var10, var35, var13);
if (this.writable && var6 != 0) {
var37 = Util.newMappedByteBuffer(var35, var7 + (long)var12, var13, var15);
return var37;
} else {
var37 = Util.newMappedByteBufferR(var35, var7 + (long)var12, var13, var15);
return var37;
}
}

map() Methods through local methods map0() Allocate a piece of virtual memory to a file , As its memory mapping area , Then it returns the starting address of this memory mapped area .

File mapping needs to be done in Java Create a MappedByteBuffer Example . If the first file mapping results in OOM, Then manually trigger garbage collection , Sleep 100ms Then try mapping , If it fails, an exception is thrown .

adopt Util Of newMappedByteBuffer ( Can read but write ) Methods or newMappedByteBufferR( Read only ) Method reflection creates a DirectByteBuffer example , among DirectByteBuffer yes MappedByteBuffer Subclasses of .

map() Method returns the starting address of the memory mapped area , adopt ( Initial address + Offset ) You can get the data of the specified memory . To some extent, it replaces read() or write() Method , The bottom layer directly uses sun.misc.Unsafe Class getByte() and putByte() Methods to read and write data .

Copyprivate native long map0(int prot, long position, long mapSize) throws IOException;

Here's the local method (native method) map0 The definition of , It passes through JNI(Java Native Interface) Call the underlying layer C The implementation of the , This native function (Java_sun_nio_ch_FileChannelImpl_map0) The implementation of JDK Source code package under the native/sun/nio/ch/FileChannelImpl.c In this source file :https://github.com/openjdk/jdk/blob/a619f36d115f1c6ebda15d7165de95dc44ebb1fd/src/java.base/windows/native/libnio/ch/FileChannelImpl.c

MappedByteBuffer The characteristics and shortcomings of :

  • MappedByteBuffer Using virtual memory out of the heap , So assign (map) The memory size of is not affected by JVM Of -Xmx Parameter limits , But there are also size limits .
  • If the file exceeds Integer.MAX_VALUE Byte limit , Can pass position Parameter reset map What's at the back of the file .
  • MappedByteBuffer It's really high performance when dealing with large files , But there is also a memory footprint 、 File closure is uncertain and so on , Files that are opened are closed only when they are garbage collected , And this point in time is uncertain .
  • MappedByteBuffer Provides file mapping memory mmap() Method , It also provides a way to free mapped memory unmap() Method . However unmap() yes FileChannelImpl Private methods in , Cannot directly display the call . therefore , The user program needs to go through Java Call of reflection sun.misc.Cleaner Class clean() Method to manually release the memory area occupied by the mapping .

2、JDK Zero copy DirectByteBuffer

DirectByteBuffer yes Java NIO A very important class for implementing off heap memory , and Netty use DirectByteBuffer As PooledDirectByteBuf and UnpooledDirectByteBuf Internal data container for ( The difference in HeapByteBuf Direct use byte[] As a data container ).

DirectByteBuffer The object reference of is located in Java In the heap of the memory model ,JVM It can be done to DirectByteBuffer Object for memory allocation and recycling management , In general use DirectByteBuffer Static method of allocateDirect() establish DirectByteBuffer Instance and allocate memory .

Copypublic static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}

DirectByteBuffer Memory allocation is to call the underlying Unsafe Class allocateMemory() Allocate out of heap memory directly :

CopyDirectByteBuffer(int cap) { // package-private
super(-1, 0, cap, cap);
boolean pa = VM.isDirectMemoryPageAligned();
int ps = Bits.pageSize();
long size = Math.max(1L, (long)cap + (pa ? ps : 0));
Bits.reserveMemory(size, cap);
long base = 0;
try {
base = unsafe.allocateMemory(size);
} catch (OutOfMemoryError x) {
Bits.unreserveMemory(size, cap);
throw x;
}
unsafe.setMemory(base, size, (byte) 0);
if (pa && (base % ps != 0)) {
// Round up to page boundary
address = base + ps - (base & (ps - 1));
} else {
address = base;
}
cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
att = null;
}

that DirectByteBuffer What does it have to do with zero copy ? Let's see DirectByteBuffer The name of the class :

Copyclass DirectByteBuffer extends MappedByteBuffer implements DirectBuffer {
}

You can see that she inherited MappedByteBuffer, and MappedByteBuffer Of map() The method will pass Util.newMappedByteBuffer() To create a buffer instance .

3、 be based on sendfile Realized FileChannel

FileChannel Is a file for reading and writing 、 Mapping and operating channels , At the same time, it is thread safe in a concurrent environment , be based on FileInputStream、FileOutputStream perhaps RandomAccessFile Of getChannel() Method to create and open a file channel .FileChannel Defined transferFrom() and transferTo() Two abstract methods , It achieves data transmission by establishing connections between channels .

transferTo(): adopt FileChannel Write the source data in the file to a WritableByteChannel The destination channel of .

transferFrom(): Put a source channel ReadableByteChannel The data in is read to the current FileChannel In the document of .

These two methods are also java.nio.channels.FileChannel Abstract method of , From subclass sun.nio.ch.FileChannelImpl.java Realization .transferTo() and transferFrom() The bottom is all based on sendfile To realize data transmission , among FileChannelImpl.java Defined 3 Constant , Used to indicate whether the kernel of the current operating system supports sendfile as well as sendfile Related characteristics of .

Copyprivate static volatile boolean transferSupported = true;
private static volatile boolean pipeSupported = true;
private static volatile boolean fileSupported = true;

transferSupported: Used to mark whether the current system kernel supports sendfile() call , The default is true.

pipeSupported: Used to mark whether the current system kernel supports file descriptors (fd) Based on the pipeline (pipe) Of sendfile() call , The default is true.

fileSupported: Used to mark whether the current system kernel supports file descriptors (fd) Based on the file (file) Of sendfile() call , The default is true.

4、Netty Zero copy

Netty The zero copy in is different from the zero copy on the operating system level mentioned above , What we say Netty Zero copy is based entirely on (Java level ) User state , It is more inclined to the concept of data operation optimization , Specifically in the following aspects :

  • Netty adopt DefaultFileRegion Class to java.nio.channels.FileChannel Of tranferTo() Method to pack , During file transfer, the data in the file buffer can be directly sent to the destination channel (Channel);
  • ByteBuf Can pass wrap Operation put byte array 、ByteBuf、ByteBuffer Pack it as a ByteBuf object , In turn, copy operation is avoided ;
  • ByteBuf Support slice operation , So you can put ByteBuf Decompose into multiple components sharing the same storage area ByteBuf, Avoid memory copy ;
  • Netty Provides CompositeByteBuf class , It can transfer multiple ByteBuf Merge into a logical ByteBuf, Avoid each ByteBuf Copy between .
copyright:author[Java program ape],Please bring the original link to reprint, thank you. https://en.javamana.com/2022/175/20210726184245584N.html