「蘑菇街技术」每个人都想听的技术解析--Netty( 二 )
零拷贝
零拷贝技术是指计算机执行操作时 , CPU不需要先将数据从某处内存复制到另一个特定区域 。 这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽 。
上面这段话摘自维基百科 , 解释也比较通俗易懂 ,零拷贝实际也就是为了减少内存与其他存储区域之间复制次数,也因此 CPU 的效率就能得以提升 , 如果按照拷贝区域来划分 , 在netty中我们可以分成这几种 , 从系统层面来说 , 就是用户空间和内核空间之间的数据拷贝 , 从java应用程序层面来说 , 包括java堆内和堆外内存之间拷贝、堆内之间的内存拷贝 。
1、减少用户和内核空间之间的数据拷贝: FileRegion
这种零拷贝主要应用于文件传输(相关使用方法见io.netty.example.http.file.HttpStaticFileServerHandler) , 其最终调用方法DefaultFileRegion.transferTo本质其实就是基于NIO的FileChannel.transferTo来实现的 。 所以我们不如直击其本源 , 直接来介绍FileChannel.transferTo这个方法 , 如下图第一个红框中的内容 , 这个方法可能比简单循环的从一个channel中读取数据再写到目标channel中更有效 , (这里划重点“可能” , 而为什么是可能呢 , 因为这依赖于操作系统底层的支持) , 许多操作系统如Linux就可以直接将字节从文件系统缓存传输到目标通道 , 而不需要实际复制它们 。 而操作系统底层又是怎么支持的呢?
文章插图
假设我们这里有个使用场景是这样的 , 我们先读取硬盘中的数据 , 然后再写出到IO设备当中;假设这是个java应用 , 首先虚拟机会通过用户空间向内核空间发送read()这样的系统调用 , 紧接着操作系统会将用户空间模式切换到内核空间模式 , 这里就会涉及到一次上下文切换 ,之后内核空间会向硬盘发出一个读取数据的请求 , 数据这个时候就会被读取到内核空间的缓冲区当中 , 注意这一步是通过DMA的方式去进行的 , 也就是direct memory access(这里有一点需要注意的是 , 一般情况下 , 硬盘或IO设备到内核空间的复制操做都是由DMA引擎执行的 , 内核空间和用户空间之间的的数据拷贝都是由cpu执行的);拷贝完之后 , 用户空间还是无法直接使用的 , 还需要在将这份数据原封不动的拷贝到用户空间的缓冲区 ,接下来你就可以继续执行你的业务逻辑代码 , 这时候 这个read操作就结束了;接着就是write方法 , 操作系统会将内核空间上的socket buffer真正的写到IO设备当中去 , 等操作完成后 , write方法就会返回;而这整个流程就会涉及到四次的上下文切换和四次数据拷贝 , 而其中内核与用户之间的两次数据拷贝 , 在我们看来是没有必要的 。 那有没有办法去减少这两次不必要的上下文切换以及数据拷贝呢?
文章插图
答案是有的 , 但是需要注意的是 , 这是得依赖于操作系统的 , 操作系统支持这样的命令才可以去进行 , Java本身是做不了任何事情的 , 这个时候实际是是调用了sendfilte的系统命令(Linux2.2起始 , 具体可见);首先也是通过直接内存访问的方式将磁盘中的数据拷贝到内核空间 , 接着将这个数据拷贝到socket 缓冲区中 , 然后拷贝sokcet缓冲区中的数据到网络IO设备中去进行数据发送 。
文章插图
但是我们发现这里有一层复制好像还是多余的 , 就是拷贝到socket缓冲区 , 庆幸的是在Linux2.4中 , 这便得到了优化 , 如下图 , 数据并未被复制到socket关联的缓冲区内 。 只是将记录数据位置和长度的描述符加入到socket缓冲区中 。 DMA模块将数据直接从内核缓冲区传递给Protocol Engine , 从而中间拷贝到socket缓冲区的这层复制 。
文章插图
2、减少Java堆内和堆外内存拷贝:DirectByteBuffer
比如这里我们举个例子 , 这里如果我们使用HeapByteBuffer进行数据读取写入的时候 , 会发生什么呢?首先你再创建的时候jvm会帮我们在堆上面去创建一个byte数组 , 但是需要注意的是 , 这个时候这个byte数组是没法直接被操作系统所使用的 , 操作系统会在Java内存模型外又会开辟一个内存区域 , 也就是将java堆上byteBuffer 会拷贝到刚刚系统开辟的内存里面 , 然后再将这里面的数据拿出来跟io设备进行交互;这里大家会不会有疑问 , 既然操作系统能访问堆上这块数据的 , 为什么不直接在上面进行操作 , 但是实际并没有这么简单 , 当我们操作系统通过JNI访问接口的时候 , 正好发生了GC,我们都知道除了cms这种使用标记清除算法之外 , 其他的垃圾回收器一般都会使用标记压缩这种方式 , 也是为了避免内存碎片 , 但是这样的话,就会找不到之前的地址了, 从而发生异常,所以直接操作是不安全的 , 直接被pass了 。
- 技术|做“视频”绿厂是专业的,这项技术获人民日报评论点赞
- 中国|浅谈5G移动通信技术的前世和今生
- 速度|华为P50Pro或采用很吓人的拍照技术:液体镜头让对焦速度更快
- 视频社会生产力报告|视频社会雏形已成,绿厂或凭这技术抢占先机
- 职工组一等|全国人工智能应用技术技能大赛落幕 青岛四名选手获一等奖
- 中国视频|人日评论点赞!OPPO成视频手机先行者,新技术或下月发布
- 介绍|5分钟介绍各种类型的人工智能技术
- 重庆市工业互联网技术创新战略联盟:构建万物互联智能工厂 助力先进制造发展
- 合并|Andre Cronje主导批量「合并」DeFi项目,是好事情吗?
- mini|电影、mini 与「当日完稿」工作流