您的位置:首页 > 科技 > 能源 > 云南公司网站制作_游戏网页制作素材_徐州seo建站_百度搜索引擎优化相关性评价

云南公司网站制作_游戏网页制作素材_徐州seo建站_百度搜索引擎优化相关性评价

2025/4/1 2:45:15 来源:https://blog.csdn.net/qq_61350148/article/details/146584885  浏览:    关键词:云南公司网站制作_游戏网页制作素材_徐州seo建站_百度搜索引擎优化相关性评价
云南公司网站制作_游戏网页制作素材_徐州seo建站_百度搜索引擎优化相关性评价

文章目录

  • 1. 什么是零拷贝?
  • 2. 为什么需要零拷贝?
    • 2.1 传统 I/O 的拷贝流程
    • 2.2 零拷贝的优化
      • 2.2.1 通过 sendfile 系统调用
      • 2.2.2 通过 mmap (内存映射) 系统调用
  • 3. Netty 实现零拷贝的方式
    • 3.1 文件传输优化:FileRegion 封装
    • 3.2 直接内存 (Direct Memory)
    • 3.3 内存映射文件:MappedByteBuffer
    • 3.4 复合缓冲区:CompositeByteBuf
    • 3.5 切片与包装操作
  • 4. 零拷贝的优点
  • 5. 总结


1. 什么是零拷贝?

零拷贝 (Zero-Copy) 是一种 通过减少或避免数据在内存之间不必要的拷贝,从而提升系统性能的技术。它主要用于 操作系统内核用户程序 之间的数据传输场景。

2. 为什么需要零拷贝?

2.1 传统 I/O 的拷贝流程

以文件传输为例,传统 I/O 的拷贝流程如下所示:

  1. 从 磁盘 读取数据到 内核缓冲区:数据从磁盘通过 DMA(直接内存访问)传输到内核空间的缓冲区。
    从 磁盘 读取数据到 内核缓冲区
  2. 将数据从 内核缓冲区 拷贝到 用户空间:用户程序通过系统调用(如 read())将内核缓冲区的数据拷贝到用户空间的缓冲区。
    将数据从 内核缓冲区 拷贝到 用户空间
  3. 将数据从 用户空间 拷贝回 内核 Socket 缓冲区:用户程序通过系统调用(如 write())将数据从用户空间缓冲区拷贝到内核空间的 Socket 缓冲区。
    将数据从 用户空间 拷贝回 内核 Socket 缓冲区
  4. 将数据从 内核 Socket 缓冲区 发送到 网络:数据通过 DMA 传输到网卡,完成发送。
    将数据从 内核 Socket 缓冲区 发送到 网络

问题:传统流程需要 4 次拷贝2 次上下文切换(用户态 和 内核态 的相互切换),性能开销大。

2.2 零拷贝的优化

零拷贝主要通过 减少用户空间与内核空间的交互 的方式减少拷贝次数,具体可以使用的特性如下:

2.2.1 通过 sendfile 系统调用

通过 sendfile,直接在内核空间将文件数据传输到 Socket 缓冲区,避免了 2 次上下文切换和 1 次拷贝。步骤如下:

磁盘->内核缓冲区
文件缓冲区->Socket 缓冲区
内核->网络

注:第二步文件从内核的 文件缓冲区 拷贝到 Socket 缓冲区 使用的是 DMA 还是 CPU 拷贝需要看硬件是否支持 SG-DMA(分散聚合直接内存访问)。

  • 若硬件(如网卡)支持 SG-DMA,数据从 文件缓冲区 到 Socket 缓冲区 的传输由 DMA 完成,无需 CPU 参与拷贝。此时,内核只需告知 DMA 控制器数据位置和长度,DMA 直接在内核空间内搬运数据,完全释放 CPU 资源,实现更高效的零拷贝
  • 若硬件不支持 SG-DMA,内核会通过 CPU 拷贝将数据从 文件缓冲区 复制到 Socket 缓冲区。

2.2.2 通过 mmap (内存映射) 系统调用

mmap 系统调用会将文件映射到进程的虚拟地址空间,使得进程可以直接访问文件内容,而无需将文件内容拷贝到用户空间的缓冲区。过程如下:

  1. 映射文件到虚拟地址空间:应用程序调用 mmap,操作系统会创建一个虚拟内存区域,并将其与文件的物理地址进行映射。此时,文件内容并没有被实际加载到内存中,只是建立了映射关系。
    映射文件到虚拟地址空间
  2. 直接访问映射区域:应用程序可以像访问普通内存一样直接访问映射区域。当应用程序访问映射区域中的某个地址时,如果该地址对应的页面尚未加载到内存中,会触发 缺页中断。操作系统会根据映射关系,将文件中的相应数据从 磁盘 读取到 内核空间的文件缓冲区,并将该页面映射到进程的虚拟地址空间。
    直接访问映射区域
  3. 将数据从 文件缓冲区 发送到到 Socket 缓冲区:当需要将文件内容发送到网络时,应用程序可以直接操作映射区域。操作系统会将内核空间的 文件缓冲区 中的数据直接拷贝到 Socket 缓冲区
    将数据从 文件缓冲区 发送到到 Socket 缓冲区
  4. 将数据从 Socket 缓冲区 发送到 网络:将数据从 Socket 缓冲区 发送到 网卡
    将数据从 Socket 缓冲区 发送到 网络

在这个过程中,数据不需要经过用户空间的缓冲区,避免了 1 次数据拷贝

注意:看似 用户空间 中好像有也一块内存,与 文件缓冲区 一样,但其实 用户空间 用 页表 来映射 文件缓冲区 中内存。

3. Netty 实现零拷贝的方式

3.1 文件传输优化:FileRegion 封装

Netty 通过 FileRegion 类封装了 NIO 的 FileChannel 类的 transferTo() 方法,避免数据 在 内核空间 与 用户空间 的拷贝上下文切换。在 Linux 操作系统中,transferTo() 底层使用 sendfile 的系统调用实现 零拷贝

3.2 直接内存 (Direct Memory)

Netty 使用 直接内存 (Direct Memory) 来减少数据在 用户空间 和 内核空间 之间的拷贝。直接内存由操作系统直接管理,避免了在 用户空间 的中转。

  • 对于文件操作,使用 mmap 进行优化。
  • 对于网络传输,使用 sendfile 进行优化。

从而避免将内核空间中 文件缓冲区 的数据拷贝到 用户空间 和 2 次上下文切换。

3.3 内存映射文件:MappedByteBuffer

通过 FileChannel.map() 将文件映射到虚拟内存,直接通过内存地址操作文件数据。底层使用了 mmap 技术,避免了 内核空间 与 用户空间 之间的 数据拷贝 和 线程切换。

3.4 复合缓冲区:CompositeByteBuf

CompositeByteBuf 将多个 ByteBuf 组合成一个逻辑上的整体,无需物理合并数据,减少内存复制

3.5 切片与包装操作

通过 ByteBuf 对象的 slice()duplicate()Unpooled.wrappedBuffer() 共享数据,而非复制数据,使用这些方法生成的 ByteBuf 与原始 ByteBuf 共用底层内存数据。

ByteBuf 除了 slice()duplicate() 方法之外,还有 retainedSlice()retainedDuplicate() 方法,这两个方法也可以实现零拷贝,而且还 增加了引用计数,避免在原始 ByteBuf 释放时意外释放共享的内存,所以更推荐调用这两个方法。

4. 零拷贝的优点

  • 降低 CPU 利用率,减少内存带宽消耗
  • 提升 I/O 密集型任务的性能

5. 总结

零拷贝并非一次拷贝都没有,它指的是尽量减少拷贝的数量,从而提升程序的性能。可优化的地方在于避免 数据在 内核空间 和 用户空间 的拷贝内核态 与 用户态 之间的上下文切换,在操作系统层面使用 sendfilemmap 就可以做到。在 Netty 中,实现零拷贝的方式有很多种,可以通过以下方式:

  • FileRegion 对象的 transfterTo() 方法
  • 直接内存
  • MappedByteBuffer
  • CompositeByteBuf
  • 切片和包装

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com