零拷贝(zerocopy)技术几张图

编程

read(file, tmp_buf, len);write(socket, tmp_buf, len);

  • 第1步调用read(),上下文切换到内核,DMA把磁盘数据复制到内核的缓存空间
  • 第2步read()返回,上下文切换到用户进程,CPU把数据复制到用户的缓存空间
  • 第3步write() 上下文切换到内核,CPU把数据复制到内核socket缓存,write返回,上下文切换的进程

第4步DMP把socket缓存数据复制到网卡缓存上

经过4次上下文切换,4次数据拷贝

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

sendfile(socket, file, len);//file可以是文件句柄,也可以是socket句柄

把文件数据通过网络发送出去,减少了上下文的切换,内核的缓存数据到直接网卡数据也不用CPU去复制,由DMA完成

  • 第1步发出sendfile系统调用,导致用户空间到内核空间的上下文切换(第一次上下文切换)。
  • 第2步通过DMA将磁盘文件中的内容拷贝到内核空间缓冲区中(第一次拷贝: hard driver ——> kernel buffer)。
  • 第3步数DMA发出中断,CPU处理中断,将数据从内核空间缓冲区拷贝到内核中与socket相关的缓冲区(第二次拷贝: kernel buffer ——> socket buffer)。
  • sendfile系统调用返回,导致内核空间到用户空间的上下文切换(第二次上下文切换)。
  • 第4步通过DMA引擎将内核空间socket缓冲区中的数据传递到网卡(第三次拷贝: socket buffer ——> 网卡)。

通过sendfile实现的零拷贝I/O只使用了2次用户空间与内核空间的上下文切换,以及3次数据的拷贝。实现了把数据从文件发送到网卡。

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

mmap(内存映射)是一个比sendfile昂贵但优于传统I/O的方法。

MappedByteBuffer

在调用FileChannel.map()时使用。 与DirectByteBuffer类似,这也是JVM堆外部的情况。 它基本上作为OS mmap()系统调用的包装函数,以便代码直接操作映射的物理内存数据。

HeapByteBuffer

在调用ByteBuffer.allocate()时使用。 它被称为堆,因为它保存在JVM的堆空间中,因此你可以获得所有优势,如GC支持和缓存优化。 但是,它不是页面对齐的,这意味着如果你需要通过JNI与本地代码交互时,比如写入网卡,写入磁盘,JVM将不得不复制到系统的页缓冲区空间。

DirectByteBuffer

在调用ByteBuffer.allocateDirect()时使用。 JVM在堆空间之外分配内存空间。 因为它不是由JVM管理的,所以你的内存空间是页面对齐的,不受GC影响,这使得它成为处理本地代码的完美选择。 然而,你要C程序员一样,自己管理这个内存,必须自己分配和释放内存来防止内存泄漏。

splice

在两个文件描述符之间传输数据,不用拷贝。但输入和输出文件描述符必须有一个是pipe。也就是说如果你需要从一个socket 传输数据到另外一个socket,是需要使用 pipe来做为中介的

splice (socket1_fd, pipe_fd) splice (pipl_fd, socket2_fd)

以上是 零拷贝(zerocopy)技术几张图 的全部内容, 来源链接: utcz.com/z/515259.html

回到顶部