NIO-零拷贝

  在传统的IO中,发起一次读请求的过程

其中发生了两次上下文的切换,以及两次内容的拷贝。其中将内容从磁盘搬运到内核缓冲区以及从内核缓存区搬运到用户缓存区都是通过cpu来完成的,这个阶段cpu不能进行其它的事情。用户线程在这个过程中都是处于阻塞状态一道IO操作完成。

引入DMA

引入DMA之后就将从磁盘拷贝内容到内存缓存区的任务交给了DMA,DMA在拷贝内容期间CPU可以干其它的事情,但是从内核缓存区拷贝到用户缓存区仍然是CPU去完成。加入DMA之后虽然CPU减少了一次数据搬运的操作,但是仍然得进行两次上下文的切换以及两次内容的拷贝。

  再来看一下传统的IO操作如果要将数据读取并且通过网络进行传输的细节

由此可以看出在一次读取文件并进行网络传输的过程中发生了四次的上下文的切换以及四次内容的拷贝。如果想要优化IO的过程可以从这两个方面去进行思考。1、减少上下文切换的次数。2、减少内容的拷贝次数。

实现零拷贝

  零拷贝的实现方式通常有两种:mmap + write、sendfile

1、mmap + write的方式

这种方式是创建一个内核和用户空间的共享映射缓存区。用户线程就可以直接操作这个映射缓存区中的内容而不用再将内容拷贝的用户空间,这样减少了一次内容的复制。写入网卡的时候调用write可以将内容直接从映射缓存区拷贝到Socket缓存区。这样减少了将内容从内核缓存区拷贝到用户缓存区以及从用户缓存区拷贝到Socket缓存区两次拷贝,增加了一次将内容从内核缓存区拷贝到Socket缓存区。

2、sendfile

第一种方式虽然减少了一次内容的拷贝,但是仍然需要四次的上下文切换。sendfile(int out_fd, int in_fd, off_t *offset, size_t count)方法将读取操作从两个独立的操作合并成一次将内容从源拷贝到目标位置的一个操作。这样只需要调用sendfile方法时从用户态切到内核态,传输成功之后再从内核态传入到用户态。减少了两次上下文的切换。但是仍需要cpu参与将内容从内核缓存区拷贝到Socket缓存区。

  真正的零拷贝应该是不需要CPU进行搬运工作。所以sendfile方法在调用的时候如果⽹卡⽀持 scatter-gather 特性那么可以将内容直接从内核缓存区拷贝到网卡。这样就不需要cpu的搬运实现了真正的零拷贝。

NIO的零拷贝

  使用nio调用transferTo()方法可以实现零拷贝。其底层就是调用了sendfile的方式实现的零拷贝。

如何通过nio实现文件的零拷贝这里就不多说了。值得注意的是nio在进行文件的传输的时候会创建一个直接内存,直接由于不属于jvm所不能被gc回收,所以直接内存的创建和回收的成本都是比较高的,但是读写性能比较高。

这里有大佬总结了使用NIO和IO进行文件操作的性能对比:大文件拷贝,试试 NIO 的内存映射_androidstarjack的博客-CSDN博客

NIO直接内存如何回收:JVM专题(九)-直接内存_IT-老牛的博客-CSDN博客_jvm直接内存

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值