这里只是感性地认识Linux零拷贝,不涉及具体细节。网络
1.Linux传统的数据拷贝socket
用户进程是不能直接访问文件系统的,要先切换到内核态,发起系统调用,DMA把磁盘中的数据写入内核空间,内核再把数据拷贝到用户空间,用户进程才能操做这些数据。spa
如上把磁盘上的文件发送到网络,将会发生4次状态切换,2次cpu拷贝。3d
2. 2.4版本前blog
(1)基于mmap(可修改数据)+write进程
将会有4次状态切换,1次cpu拷贝。ip
由于内存映射老是要对齐页边界(最小单位为4kb),因此可能会形成碎片空间的浪费,一个5kb的文件要映射占用8kb的空间,浪费了3kb。内存
(2)基于sendFile(不可修改数据,jdk nio中transferFrom,transferTo,数据从一个channel直接传输到另外一个channel即是依赖于此)it
将会有2次状态切换,1次cpu拷贝。pip
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拷贝。