没有合适的资源?快使用搜索试试~ 我知道了~
首页Linux I/O 原理和 Zero-copy 技术全面揭秘
两万字长文从虚拟内存、I/O 缓冲区,用户态&内核态以及 I/O 模式等等知识点全面而又详尽地剖析 Linux 系统的 I/O 底层原理,分析了 Linux 传统的 I/O 模式的弊端,进而引入 Linux Zero-copy 零拷贝技术的介绍和原理解析,将零拷贝技术和传统的 I/O 模式进行区分和对比,帮助读者理解 Linux 内核对 I/O 模块的优化改进思路。 全网最深度和详尽的 Linux I/O 及零拷贝技术的解析文章。
资源详情
资源评论
资源推荐
Linux I/O 原理和 Zero-copy 技术全面揭秘
导言
如今的网络应用早已从 CPU 密集型转向了 I/O 密集型,网络服务器大多是基于 C-S 模型,
也即 客户端 - 服务端 模型,客户端需要和服务端进行大量的网络通信,这也决定了现代网络
应用的性能瓶颈:I/O。
传统的 Linux 操作系统的标准 I/O 接口是基于数据拷贝操作的,即 I/O 操作会导致数据在
操作系统内核地址空间的缓冲区和用户进程地址空间定义的缓冲区之间进行传输。设置缓冲
区最大的好处是可以减少磁盘 I/O 的操作,如果所请求的数据已经存放在操作系统的高速
缓冲存储器中,那么就不需要再进行实际的物理磁盘 I/O 操作;然而传统的 Linux I/O 在
数据传输过程中的数据拷贝操作深度依赖 CPU,也就是说 I/O 过程需要 CPU 去执行数据
拷贝的操作,因此导致了极大的系统开销,限制了操作系统有效进行数据传输操作的能力。
I/O 是决定网络服务器性能瓶颈的关键,而传统的 Linux I/O 机制又会导致大量的数据拷贝
操作,损耗性能,所以我们亟需一种新的技术来解决数据大量拷贝的问题,这个答案就是零
拷贝(Zero-copy)。
计算机存储器
既然要分析 Linux I/O,就不能不了解计算机的各类存储器。
存储器是计算机的核心部件之一,在完全理想的状态下,存储器应该要同时具备以下三种特
性:
1. 速度足够快:存储器的存取速度应当快于 CPU 执行一条指令,这样 CPU 的效率
才不会受限于存储器
2. 容量足够大:容量能够存储计算机所需的全部数据
3. 价格足够便宜:价格低廉,所有类型的计算机都能配备
但是现实往往是残酷的,我们目前的计算机技术无法同时满足上述的三个条件,于是现代计
算机的存储器设计采用了一种分层次的结构:
从顶至底,现代计算机里的存储器类型分别有:寄存器、高速缓存、主存和磁盘,这些存储
器的速度和容量逐级递减。存取速度最快的是寄存器,因为寄存器的制作材料和 CPU 是相
同的,所以速度和 CPU 一样快,CPU 访问寄存器是没有时延的,然而因为价格昂贵,因
此容量也极小,一般 32 位的 CPU 配备的寄存器容量是 3232 Bit,64 位的 CPU 则是
6464 Bit,不管是 32 位还是 64 位,寄存器容量都小于 1 KB,且寄存器也必须通过软
件自行管理。
第二层是高速缓存,也即我们平时了解的 CPU 高速缓存 L1、L2、L3,一般 L1 是每个 CPU
独享,L3 是全部 CPU 共享,而 L2 则根据不同的架构设计会被设计成独享或者共享两种
模式之一,比如 Intel 的多核芯片采用的是共享 L2 模式而 AMD 的多核芯片则采用的是
独享 L2 模式。
第三层则是主存,也即主内存,通常称作随机访问存储器(Random Access Memory, RAM)。
是与 CPU 直接交换数据的内部存储器。它可以随时读写(刷新时除外),而且速度很快,
通常作为操作系统或其他正在运行中的程序的临时资料存储介质。
最后则是磁盘,磁盘和主存相比,每个二进制位的成本低了两个数量级,因此容量比之会大
得多,动辄上 GB、TB,而问题是访问速度则比主存慢了大概三个数量级。机械硬盘速度
慢主要是因为机械臂需要不断在金属盘片之间移动,等待磁盘扇区旋转至磁头之下,然后才
能进行读写操作,因此效率很低。
主内存是操作系统进行 I/O 操作的重中之重,绝大部分的工作都是在用户进程和内核的内
存缓冲区里完成的,因此我们接下来需要提前学习一些主存的相关原理。
物理内存
我们平时一直提及的物理内存就是上文中对应的第三种计算机存储器,RAM 主存,它在计
算机中以内存条的形式存在,嵌在主板的内存槽上,用来加载各式各样的程序与数据以供
CPU 直接运行和使用。
虚拟内存
在计算机领域有一句如同摩西十诫般神圣的哲言:“计算机科学领域的任何问题都可以通过
增加一个间接的中间层来解决”,从内存管理、网络模型、并发调度甚至是硬件架构,都能
看到这句哲言在闪烁着光芒,而虚拟内存则是这一哲言的完美实践之一。
虚拟内存是现代计算机中的一个非常重要的存储器抽象,主要是用来解决应用程序日益增长
的内存使用需求:现代物理内存的容量增长已经非常快速了,然而还是跟不上应用程序对主
存需求的增长速度,对于应用程序来说内存还是不够用,因此便需要一种方法来解决这两者
之间的容量差矛盾。
计算机对多程序内存访问的管理经历了 静态重定位 --> 动态重定位 --> 交换(swapping)技
术 --> 虚拟内存,最原始的多程序内存访问是直接访问绝对内存地址,这种方式几乎是完全不
可用的方案,因为如果每一个程序都直接访问物理内存地址的话,比如两个程序并发执行以
下指令的时候:
mov cx, 2
mov bx, 1000H
mov ds, bx
mov [0], cx
...
mov ax, [0]
add ax, ax
这一段汇编表示在地址 1000:0 处存入数值 2,然后在后面的逻辑中把该地址的值取出来乘
以 2,最终存入 ax 寄存器的值就是 4,如果第二个程序存入 cx 寄存器里的值是 3,那
么并发执行的时候,第一个程序最终从 ax 寄存器里得到的值就可能是 6,这就完全错误了,
得到脏数据还顶多算程序结果错误,要是其他程序往特定的地址里写入一些危险的指令而被
另一个程序取出来执行,还可能会导致整个系统的崩溃。所以,为了确保进程间互不干扰,
每一个用户进程都需要实时知晓当前其他进程在使用哪些内存地址,这对于写程序的人来说
无疑是一场噩梦。
因此,操作绝对内存地址是完全不可行的方案,那就只能用操作相对内存地址,我们知道每
个进程都会有自己的进程地址,从 0 开始,可以通过相对地址来访问内存,但是这同样有
问题,还是前面类似的问题,比如有两个大小为 16KB 的程序 A 和 B,现在它们都被加
载进了内存,内存地址段分别是 0 ~ 16384,16384 ~ 32768。A 的第一条指令是 jmp 1024,
而在地址 1024 处是一条 mov 指令,下一条指令是 add,基于前面的 mov 指令做加法运算,
与此同时,B 的第一条指令是 jmp 1028,本来在 B 的相对地址 1028 处应该也是一
条 mov 去操作自己的内存地址上的值,但是由于这两个程序共享了段寄存器,因此虽然他们
使用了各自的相对地址,但是依然操作的还是绝对内存地址,于是 B 就会跳去执行 add 指
令,这时候就会因为非法的内存操作而 crash。
有一种静态重定位的技术可以解决这个问题,它的工作原理非常简单粗暴:当 B 程序被加载
到地址 16384 处之后,把 B 的所有相对内存地址都加上 16384,这样的话当 B 执行 jmp
1028 之时,其实执行的是 jmp 1028+16384,就可以跳转到正确的内存地址处去执行正确的
指令了,但是这种技术并不通用,而且还会对程序装载进内存的性能有影响。
再往后,就发展出来了存储器抽象:地址空间,就好像进程是 CPU 的抽象,地址空间则是
存储器的抽象,每个进程都会分配独享的地址空间,但是独享的地址空间又带来了新的问题:
如何实现不同进程的相同相对地址指向不同的物理地址?最开始是使用动态重定位技术来实
现,这是用一种相对简单的地址空间到物理内存的映射方法。基本原理就是为每一个 CPU
配备两个特殊的硬件寄存器:基址寄存器和界限寄存器,用来动态保存每一个程序的起始物
理内存地址和长度,比如前文中的 A,B 两个程序,当 A 运行时基址寄存器和界限寄存器
就会分别存入 0 和 16384,而当 B 运行时则两个寄存器又会分别存入 16384 和 32768。
然后每次访问指定的内存地址时,CPU 会在把地址发往内存总线之前自动把基址寄存器里
的值加到该内存地址上,得到一个真正的物理内存地址,同时还会根据界限寄存器里的值检
查该地址是否溢出,若是,则产生错误中止程序,动态重定位技术解决了静态重定位技术造成
的程序装载速度慢的问题,但是也有新问题:每次访问内存都需要进行加法和比较运算,比
较运算本身可以很快,但是加法运算由于进位传递时间的问题,除非使用特殊的电路,否则
会比较慢。
然后就是 交换(swapping)技术,这种技术简单来说就是动态地把程序在内存和磁盘之间进
行交换保存,要运行一个进程的时候就把程序的代码段和数据段调入内存,然后再把程序封
存,存入磁盘,如此反复。为什么要这么麻烦?因为前面那两种重定位技术的前提条件是计
算机内存足够大,能够把所有要运行的进程地址空间都加载进主存,才能够并发运行这些进
程,但是现实往往不是如此,内存的大小总是有限的,所有就需要另一类方法来处理内存超
载的情况,第一种便是简单的交换技术:
先把进程 A 换入内存,然后启动进程 B 和 C,也换入内存,接着 A 被从内存交换到磁
盘,然后又有新的进程 D 调入内存,用了 A 退出之后空出来的内存空间,最后 A 又被重
新换入内存,由于内存布局已经发生了变化,所以 A 在换入内存之时会通过软件或者在运
行期间通过硬件(基址寄存器和界限寄存器)对其内存地址进行重定位,多数情况下都是通
过硬件。
另一种处理内存超载的技术就是虚拟内存技术了,它比交换(swapping)技术更复杂而又更高
效,是目前最新应用最广泛的存储器抽象技术:
虚拟内存的核心原理是:为每个程序设置一段"连续"的虚拟地址空间,把这个地址空间分割
成多个具有连续地址范围的页 (page),并把这些页和物理内存做映射,在程序运行期间动
态映射到物理内存。当程序引用到一段在物理内存的地址空间时,由硬件立刻执行必要的映
射;而当程序引用到一段不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入
物理内存并重新执行失败的指令:
剩余42页未读,继续阅读
羽黯
- 粉丝: 3
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- zigbee-cluster-library-specification
- JSBSim Reference Manual
- c++校园超市商品信息管理系统课程设计说明书(含源代码) (2).pdf
- 建筑供配电系统相关课件.pptx
- 企业管理规章制度及管理模式.doc
- vb打开摄像头.doc
- 云计算-可信计算中认证协议改进方案.pdf
- [详细完整版]单片机编程4.ppt
- c语言常用算法.pdf
- c++经典程序代码大全.pdf
- 单片机数字时钟资料.doc
- 11项目管理前沿1.0.pptx
- 基于ssm的“魅力”繁峙宣传网站的设计与实现论文.doc
- 智慧交通综合解决方案.pptx
- 建筑防潮设计-PowerPointPresentati.pptx
- SPC统计过程控制程序.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0