深入理解Os--补充内容

发布时间:2026/7/22 20:47:39
深入理解Os--补充内容 1.指令的执行速度CPU 的硬件参数都会有GHz 这个参数比如一个1 GHz的 CPU指的是时钟频率是 1 G代表着 1 秒会产生 1G 次的脉冲信号每一次脉冲信号高低电平的转换就是一个周期称为时钟周期。对于 CPU 来说在一个时钟周期内CPU 仅能完成一个最基本的动作。时钟频率越高时钟周期就越短工作速度也就越快。一个时钟周期一定能执行完一条指令吗答案是不一定的大多数指令不能在一个时钟周期完成通常需要若干个时钟周期。不同的指令需要的时钟周期是不同的加法和乘法都对应着一条 CPU 指令但是乘法需要的时钟周期就要比加法多。2.64 位相比 32 位 CPU 的优势在哪吗64 位 CPU 的计算性能一定比 32 位 CPU 高很多吗64 位相比 32 位 CPU 的优势主要体现在两个方面a.64 位 CPU 可以一次计算超过 32 位的数字而 32 位 CPU 如果要计算超过 32 位的数字要分多步骤进行计算效率就没那么高但是大部分应用程序很少会计算那么大的数字所以只有运算大数字的时候64 位 CPU 的优势才能体现出来否则和 32 位 CPU 的计算性能相差不大。b.通常来说 64 位 CPU 的地址总线是 48 位而 32 位 CPU 的地址总线是 32 位所以 64 位 CPU 可以寻址更大的物理内存空间。如果一个 32 位 CPU 的地址总线是 32 位那么该 CPU 最大寻址能力是 4G即使你加了 8G 大小的物理内存也还是只能寻址到 4G 大小的地址而如果一个 64 位 CPU 的地址总线是 48 位那么该 CPU 最大寻址能力是 2^48远超于 32 位 CPU 最大寻址能力。3.你知道软件的 32 位和 64 位之间的区别吗再来 32 位的操作系统可以运行在 64 位的电脑上吗64 位的操作系统可以运行在 32 位的电脑上吗如果不行原因是什么64 位和 32 位软件实际上代表指令是 64 位还是 32 位的a.如果 32 位指令在 64 位机器上执行需要一套兼容机制就可以做到兼容运行了。但是如果 64 位指令在 32 位机器上执行就比较困难了因为 32 位的寄存器存不下 64 位的指令b.操作系统其实也是一种程序我们也会看到操作系统会分成 32 位操作系统、64 位操作系统其代表意义就是操作系统中程序的指令是多少位比如 64 位操作系统指令也就是 64 位因此不能装在 32 位机器上。总之硬件的 64 位和 32 位指的是 CPU 的位宽软件的 64 位和 32 位指的是指令的位宽。4.CPU Cache5.存储器层次每个存储器只和相邻的一层存储器设备打交道当 CPU 需要访问内存中某个数据的时候如果寄存器有这个数据CPU 就直接从寄存器取数据即可如果寄存器没有这个数据CPU 就会查询 L1 高速缓存如果 L1 没有则查询 L2 高速缓存L2 还是没有的话就查询 L3 高速缓存L3 依然没有的话才去内存中取数据。6.访问速度7.如何写出让 CPU 跑得更快的代码A.提升「数据缓存」的缓存命中率连续数据访问时尽量按照内存布局顺序访问将可以有效的利用 CPU Cache 带来的好处这样我们代码的性能就会得到很大的提升B.提升「指令缓存」的缓存命中率CPU 的分支预测器如果分支预测可以预测到接下来要执行 if 里的指令还是 else 指令的话就可以「提前」把这些指令放在指令缓存中这样 CPU 可以直接从 Cache 读取到指令于是执行速度就会很快。分支预测器会动态地根据历史命中数据对未来进行预测基于此尽量控制频繁执行分支语句连续命中同一分支如果你肯定代码中的 if 中的表达式判断为 true 的概率比较高我们可以使用显示分支预测工具比如在 C/C 语言中编译器提供了 likely 和 unlikely 这两种宏如果 if 条件为 ture 的概率大则可以用 likely 宏把 if 里的表达式包裹起来反之用 unlikely 宏。实际上CPU 自身的动态分支预测已经是比较准的了所以只有当非常确信 CPU 预测的不准且能够知道实际的概率情况时才建议使用这两种宏。C.提升多核 CPU 的缓存命中率L3 Cache 是多核心之间共享的但是 L1 和 L2 Cache 都是每个核心独有的如果一个线程在不同核心来回切换各个核心的缓存命中率就会受到影响相反如果线程都在同一个核心上执行那么其数据的 L1 和L2 Cache 的缓存命中率可以得到有效提高有多个同时执行「计算密集型」的线程时可以把每个线程绑定在某一个 CPU 核心上8.单核CPU 缓存一致性两种针对写入数据的方法写直达Write Through写回Write Back写直达把数据同时写入内存和 Cache 在这个方法里写入前会先判断数据是否已经在 CPU Cache 里面了如果数据已经在 Cache 里面先将数据更新到 Cache 里面再写入到内存里面如果数据没有在 Cache 里面就直接把数据更新到内存里面。写回:当发生写操作时新的数据仅仅被写入 Cache Block 里只有当修改过的 Cache Block「被替换」时才需要写到内存中如果当发生写操作时数据已经在 CPU Cache 里的话则把数据更新到 CPU Cache 里同时标记 CPU Cache 里的这个 Cache Block 为脏Dirty的这个脏的标记代表这个时候我们 CPU Cache 里面的这个 Cache Block 的数据和内存是不一致的这种情况是不用把数据写到内存里的如果当发生写操作时数据所对应的 Cache Block 里存放的是「别的内存地址的数据」的话就要检查这个 Cache Block 里的数据有没有被标记为脏的1.如果是脏的话我们就要把这个 Cache Block 里的数据写回到内存然后再把当前要写入的数据先从内存读入到 Cache Block 里然后再把当前要写入的数据写入到 Cache Block最后也把它标记为脏的2.如果不是脏的话把当前要写入的数据先从内存读入到 Cache Block 里接着将数据写入到这个 Cache Block 里然后再把这个 Cache Block 标记为脏的就好了。9.多核缓存一致性问题采用写回策略运行在不同核心的线程访问共享变量时线程修改了变量线程此后访问变量由于写回若未采取一致性处理策略线程所在核心的数据缓存里此时通过内存将访问到不一致的变量值实现多核下一致性要保证做到下面这 2 点第一点某个 CPU 核心里的 Cache 数据更新时必须要传播到其他核心的 Cache这个称为写传播Write Propagation第二点某个 CPU 核心里对数据的操作顺序必须在其他核心看起来顺序是一样的这个称为事务的串行化Transaction Serialization。比如四个线程运行在个核心操作共享变量线程将其设置为线程将其设置为线程线程需按照一致的顺序收到通知如先改为再改为一致性实现技术总线嗅探MESI 协议10.总线嗅探举例当 A 号 CPU 核心修改了 L1 Cache 中 i 变量的值通过总线把这个事件广播通知给其他所有的核心然后每个 CPU 核心都会监听总线上的广播事件并检查是否有相同的数据在自己的 L1 Cache 里面如果 B 号 CPU 核心的 L1 Cache 中有该数据那么也需要把该数据更新到自己的 L1 Cache。总线嗅探方法很简单 CPU 需要每时每刻监听总线上的一切活动无疑会加重总线的负载。另外总线嗅探只是保证了某个 CPU 核心的 Cache 更新数据这个事件能被其他 CPU 核心知道但是并不能保证事务串行化。MESI 协议基于总线嗅探机制实现了事务串行化也用状态机机制降低了总线带宽压力11.MESI 协议MESI 协议其实是 4 个状态单词的开头字母缩写分别是Modified已修改代表该 Cache Block 上的数据已经被更新过但是还没有写到内存里。Exclusive独占这个时候 Cache Block 里的数据和内存里面的数据是一致性的。数据只存储在一个 CPU 核心的 Cache 里Shared共享这个时候 Cache Block 里的数据和内存里面的数据是一致性的。数据存储在多个 CPU 核心的 Cache 里Invalidated已失效这个 Cache Block 里的数据已经失效了不可以读取该状态的数据。此协议下每个核心读写数据时先结合自身状态看是否可以立即完成操作无法立即完成的广播通知其他cpu再执行操作