NIO学习笔记,从Linux IO演化模型到Netty—— Linux零拷贝
这里只是感性地认识Linux零拷贝,不涉及具体细节。
1.Linux传统的数据拷贝
用户进程是不能直接访问文件系统的,要先切换到内核态,发起系统调用,DMA把磁盘中的数据写入内核空间,内核再把数据拷贝到用户空间,用户进程才能操作这些数据。
如上把磁盘上的文件发送到网络,将会发生4次状态切换,2次cpu拷贝。
2. 2.4版本前
(1)基于mmap(可修改数据)+write
将会有4次状态切换,1次cpu拷贝。
因为内存映射总是要对齐页边界(最小单位为4kb),所以可能会造成碎片空间的浪费,一个5kb的文件要映射占用8kb的空间,浪费了3kb。
(2)基于sendFile(不可修改数据,jdk nio中transferFrom,transferTo,数据从一个channel直接传输到另一个channel便是依赖于此)
将会有2次状态切换,1次cpu拷贝。
3. 2.4版本后,基于mmap(用于修改数据,后续版本中如果共享区为多个进程共有,将会写时复制,拷贝到用户空间)+gather
Linux 2.4 版本的内核对 sendfile 系统调用进行修改,为 DMA (要硬件支持)拷贝引入了 gather 操作。它将内核空间(kernel space)的读缓冲区(read buffer)中对应的数据描述信息(内存地址、地址偏移量)记录到相应的网络缓冲区( socket buffer)中,由 DMA 根据内存地址、地址偏移量将数据批量地从读缓冲区(read buffer)拷贝到网卡设备中。
将有2次状态切换,0次cpu拷贝。
4. 2.6.17版本后,splice(用户进程不能修改数据)
splice 系统调用(不需硬件支持)可以在内核空间的读缓冲区(read buffer)和网络缓冲区(socket buffer)之间建立管道(pipeline),从而避免了两者之间的 CPU 拷贝操作。
将有2次状态切换,0次cpu拷贝。