零拷贝剖析

一 一次普通网络请求资源的过程

image.png

1.1具体步骤说明

1.用户空间对内核空间发出一次read()的系统调用
2.操作系统接收到系统调用后,上下文切换。切换到了内核空间
3.内核空间向磁盘请求数据, 通过DMA将数据发送到了内核空间缓存区
4.将内核空间缓冲区的数据原封不动地拷贝到了用户空间缓存区。
==第二阶段=
5.jvm发出wirte()的系统调用,并且将用户空间缓存区的数据搬回了内核空间缓冲区。这个缓冲区和上面的缓冲区不一样,这个是属于socket的缓冲区(是内核空间,但不和上面一样。只要发送就需要配先放到socket缓冲区
6.将内核空间缓存区的数据写到网络
7.wirte()返回。

总结
1.一共存在4次上下文的切换
2.两次不必要的拷贝。

二 操作系统意义上的零拷贝

首先需要操作系统提供支持,纯技术(语言层面)上无法实现
image.png
没有数据和用户空间交互

nio中的MapByteBuffer就是一种实现,transTo,transFrom如果底层操作系统支持,就会使用零拷贝

三 进一步改善

image.png

总结
上面两种都是零拷贝,nio都会使用。主要看底层操作系统是否支持更好的那种

四 缓存IO、直接IO与内存映射

缓存IO对应第一节
image.png

直接IO对应第二节
image.png

直接内存映射
如果说直接IO和缓存IO是相对的、而内存映射是另外一个概念
image.png

内存映射方式是指操作系统将内存中的某一块区域与磁盘中的文件关联起来、当要访问内存中一段数据时、转换为访问文件的某一段数据、这种方式的目的同样是减少数据从内核空间缓存到用户空间缓存的数据复制操作、因为这两个空间的数据是共享的

所以直接内存映射还是将数据读取到了内核空间,只不过不需要继续拷贝`到用户空间。

Java NIO Buffer中的非直接缓冲区指的就是缓存IO、而直接缓冲区并不是Linux概念上面的直接IO、而是内存映射、请看下面的对比图
image.png
image.png

Java NIO中建立直接缓冲区、其实是在JVM内存外开辟堆外内存、在每次调用基础操作系统的一个本机IO之前或者之后、虚拟机都会避免将缓冲区的内容复制到中间缓冲区(或者从中间缓冲区复制内容)、缓冲区的内容驻留在物理内存内、会少一次复制过程、如果需要循环使用缓冲区、用直接缓冲区可以很大地提高性能、虽然直接缓冲区使JVM可以进行高效的IO操作、但它使用的内存是操作系统分配的、绕过了JVM堆栈、nmap的建立和销毁比堆栈上的缓冲区要更大的开销

参考:缓存IO、直接IO与内存映射

五 linux上真正的零拷贝

image.png
这是一次网络IO
原来有3次拷贝(最后一次可不算,那就是两次)

  1. 磁盘到内核空间
  2. 内核空间到socket缓存区
  3. socket缓存区到protocol engine(协议引擎,真正网络发送的地方。)

现在两次(最后一次可不算)

  1. 磁盘到内核空间
  2. 内核空间到socket缓存区(不拷贝数据,只存储了内核空间数据对应的文件描述符)
  3. protocol engine结合socket缓存区(文件描述符)和内核空间读数据(第二次拷贝)

什么是零拷贝?
就是只读取一次,将数据从磁盘读取到内存。(协议引擎的读取不算)
上面通过transTo发送,底层就是用到了零拷贝

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值