40-理解内存(上):虚拟内存和内存保护是什么?
- 问题:虚拟内存地址怎么映射到物理内存地址?
- 解决:简单页表
简单页表
用映射表来映射虚拟内存地址和物理内存。每个表项高位为虚拟页号,低位为偏移量
内存地址转换的步骤
- 把虚拟内存地址(一串数),切分成页号和偏移量的组合
- 根据虚拟页号,在页表里,查询对应的物理页号
- 拿到物理页号,加上前面的偏移量,就得到了物理内存地址
多级页表
-
问题:程序占用的内存空间有限,如何优化页表存储大小?
-
特点:进程常常使用两头的内存地址,而且虚拟内存地址分布具有连续性(不用哈希表)
-
解决:多级页表(Multi-Level Page Table)
多级页表就像一个多叉树的数据结构,所以我们常常称它为页表树(Page Table Tree)
-
优点:因为连续性,树的一级节点都是空的,不用储存大量的空页项
-
缺点:以时间换空 间。查询页面需要多次访问内存。
- 解决:TLB
41-理解内存(下):解析TLB和内存保护
-
问题:如何提升地址转换的效率?
-
解决:TLB来缓存地址查询的结果
-
解决:MMU。用硬件来执行地址转换
-
问题:如何解决地址转换的安全性问题?
-
解决:可执行空间保护
-
只有指令部分设置成可执行,防止数据部分命令注入
(因为指令和数据都是二进制数字串,区别在于对数字的解释方法不同)
-
-
解决:地址空间布局随机化
- 地址空间布局随机化使破坏者无法修改有效的内容位置
内存管理单元 (MMU,Memory Management Unit)
TLB,全称是地址变换高 速缓冲(Translation-Lookaside Buffer)。
执行空间保护(Executable Space Protection)
地址空间布局随机化(Address Space Layout Randomization)
数据加盐再进行MD5加密也是利用了 “随机化”策略
加速地址转换:TLB
MMU
安全性与内存保护
可执行空间保护
地址空间布局随机化
42-总线:计算机内部的高速公路
计算机是用什么样的方式来完成,CPU和内存、以及外部输入输出设备的通信呢? 这个问题就是我们今天要讲的主题,也就是总线。
降低复杂性:总线的设计思路来源
- 问题:设备之间怎么通信?
- 解决:各个点对点连接
- 问题:n个设备系统复杂度会变成n^2。怎么降低复杂度?
- 解决:各个设备连接到总线,总线公用
在事件总线这个设计模式里,各个模块触发对应的事件,并把事件对象发送到总线上。也就是说,每个模块 都是一个发布者(Publisher)。而各个模块也会把自己注册到总线上,去监听总线上的事件,并根据事件 的对象类型或者是对象内容,来决定自己是否要进行特定的处理或者响应。
这样的设计下,注册在总线上的各个模块就是松耦合的。模块互相之间并没有依赖关系。无论代码的维护, 还是未来的扩展,都会很方便。
理解总线:三种线路和多总线架构
-
双独立总线 (Dual Independent Bus,缩写为DIB)。CPU里,有一个快速的本地总线(Local Bus),以及一个速度相 对较慢的前端总线(Front-side Bus)。
- 高速本地总线,就是用来和高速缓存通信的。而前端总线,则是用来和主内存以及输入输出设备通信的。
前端总线,其实就是系统总线。CPU里面的内存接口,直接和系统总线通信,然后系统总线再接入一 个I/O桥接器(I/O Bridge)。这个I/O桥接器,一边接入了我们的内存总线,使得我们的CPU和内存通信; 另一边呢,又接入了一个I/O总线,用来连接I/O设备。
总线有三类线路。
- 数据线(Data Bus),用来传输实际的数据信息
- 地址线(Address Bus),缺点传输的目的地址
- 控制线(Control Bus),用来控制对于总线的访问
- 问题:总线只能单独使用,多个设备同时使用总线会产生资源竞争
- 解决:总线裁决(Bus Arbitraction)
43-输入输出设备:我们并不是只能用灯泡显示“0”和“1”
接⼝和设备:经典的适配器模式
I/O设备由接 ⼝(Interface)和实际的I/O设备(Actual I/O Device)组成。硬件设备通过接口接入总线再通过总线和CPU通信
CPU是如何控制I/O设备的?
通过这个控制电路,CPU才能通过向这个接⼝电路板传输信号,来控制实际的硬件
- 数据寄存器(Data Register)。CPU向I/O设备写⼊需要传输的数据
- 命令寄存器(Command Register)。储存需要执行的命令
- 状态寄存器(Status Register),储存I/O设备的工作状态
信号和地址:发挥总线的价值
- 问题:CPU如何和i/o设备通信?
- 问题:如何映射i/o设备?
- 解决:内存映射I/O(MMIO)
- 原理:把I/O设备的各个寄存器,以及I/O设备内部的内存地址,都映射到主内存地址空间⾥来。
- 优点:可以使用操作内存的指令来操作i/o设备
- 解决: 端口映射IO( PMIO)
- PMIO⾥⾯访问的设备地址,是⼀个专⻔的端⼝(Port)。
- 问题:映射完成后的执行过程?
- 答案:CPU把数据传到I/O设备对应的地址设备的接⼝电路把数据解码成指令后,再通过控制电路去操作实际的硬件设备
内存映射IO(Memory-Mapped I/O,简称 MMIO)
端口映射IO:(Port mapped I/O,MMIO)
总结延伸
CPU并不是发送⼀个特定的操作指令来操作不同的I/O设备。
⾸先,在I/O设备这⼀侧,我们把I/O设备拆分成,能和CPU通信的接⼝电路,以及实际的I/O设备本⾝。接 ⼝电路⾥⾯有对应的状态寄存器、命令寄存器、数据寄存器、数据缓冲区和设备内存等等。接⼝电路通过总 线和CPU通信,接收来⾃CPU的指令和数据。⽽接⼝电路中的控制电路,再解码接收到的指令,实际去操作 对应的硬件设备。
I/O设备
- 接⼝电路
- 有状态寄存器、命令寄存器、数据寄存器、数据缓冲区和设备内存等等
- 接⼝电路通过总 线和CPU通信,接收来⾃CPU的指令和数据。
- ⼝电路中的控制电路,再解码接收到的指令,实际去操作 对应的硬件设备。
- 实际的I/O设备本⾝
CPU
- 向内存地址或者端⼝地址传输指令和数据,所以硬件层面使用通用的指令
44-理解IO_WAIT:IO性能到底是怎么回事⼉?
计算机组成原理这⻔课⾥⾯,很多设计的核⼼思路,都来源于性能。
IO性能、顺序访问和随机访问
性能指标
- 响应时间(Response Time):程序发起⼀个硬盘的写⼊请求,直到这个请求返回的时间。
- 数据传输率(Data Transfer Rate)
- IOPS:每秒输⼊输出操作的次数。
- 随机读写的IOPS。是服务器性能的核⼼指标。
硬盘种类
- HDD:机械硬盘
- SSD:固态硬盘
HDD用SATA 3.0的接⼝。SDD慢的用SATA 3.0;快的用PCI Express的接⼝。
HDD硬盘的IOPS通常也就在100左右
如何定位IO_WAIT?
即使是⽤上了PCI Express接⼝的SSD硬盘,IOPS也就是在2万左右。⽽我们的CPU的主频通常在 2GHz以上,也就是每秒可以做20亿次操作。
即使CPU向硬盘发起⼀条读写指令,需要很多个时钟周期,⼀秒钟CPU能够执⾏的指令数,和我们硬盘能够 进⾏的操作数,也有好⼏个数量级的差异。
在实际遇到服务端程序的性能问题的时候,我们怎么知道这个问题是不是来⾃于CPU等I/O来完成操 作呢?
在top命令⾥⾯,我们⼀样可以看到CPU是否在等待IO操作完成。
有⼀⾏是以%CPU开头的。这⼀⾏⾥,有⼀个叫作wa的指标,这个指标就代表 着iowait,也就是CPU等待IO完成操作花费的时间占CPU的百分⽐。
知道了iowait很⼤,那么我们就要去看⼀看,实际的I/O操作情况是什么样的。这个时候,你就可以去⽤ iostat这个命令了。我们输⼊“iostat”,就能够看到实际的硬盘读写情况。
这⾥的tps指标,其实就对应着我们上⾯所说的硬盘的IOPS性能。⽽kB_read/s和kB_wrtn/s指标,就对应 着我们的数据传输率的指标。
。那么,接下来,我们就是要找出到底是哪⼀个进程是这些I/O读写的来源了。这个时候,你需 要“iotop”这个命令。
通过iotop这个命令,你可以看到具体是哪⼀个进程实际占⽤了⼤量I/O
总结延伸
这⼀讲⾥,我们从硬盘的两个核⼼指标,响应时间和数据传输率,来理解和研究I/O的性能问题。你也⾃⼰ 可以通过as ssd这样的性能评测软件,看⼀看⾃⼰的硬盘性能。
45-机械硬盘:Google早期⽤过的“⿊科技”
拆解机械硬盘
我们说,机械硬盘的IOPS,⼤概只能做到每秒100次左右。那 么,这个100次究竟是怎么来的呢?
-
盘⾯(Disk Platter):其实就是我们实际存储数据的盘⽚。
-
硬盘的转速:指的就是盘⾯中间电机控制的转轴的旋转速度
英⽂单位叫RPM,也就 是每分钟的旋转圈数(Rotations Per Minute)。 7200RPM也就是120圈/秒
-
磁头(Drive Head):数据是通过磁头, 从盘⾯上读取到,然后再通过电路信号传输给控制电路、接⼝,再到总线上的。
-
看悬臂(Actutor Arm):悬臂链接在磁头上,并且在⼀定范围内会去把磁头定位到盘⾯的某个 特定的磁道(Track)上
-
⼀个磁道,会分成⼀个⼀个扇区(Sector)。上下平⾏的⼀个⼀个盘⾯的相同扇区呢,我们叫 作⼀个柱⾯(Cylinder)。
读取数据:先旋转盘面,再移动悬臂
所以一次随机访问有两段时间:旋转盘面:平均延时(Average Latency)。移动悬臂:平均寻道时间(Average Seek Time)
- 问题:进⾏顺序的数据读写,我们应该怎么最⼤化读取效率呢?
- 解决:把顺序存放的数据,放在同⼀个柱⾯上。只需要一次旋转盘面和寻址就可以读写一个柱面的数据。接着可以旋转盘面顺序读写一个磁道上的数据
Partial Stroking:根据场景提升性能
-
问题:如何提升IOPS?
-
思路:访问⼀次数据的时间,是“平均延时+寻道 时间”。缩短一个
一般寻道时间>平均时延
-
解决:只使用外侧部分磁道来减少寻道时间