理解计算机系统_虚拟内存(二)缓存
前言
以<深入理解计算机系统>(以下称“本书”)内容为基础,对程序的整个过程进行梳理。本书内容对整个计算机系统做了系统性导引,每部分内容都是单独的一门课.学习深度根据自己需要来定
引入
接续上一帖
物理和虚拟寻址
1>物理寻址
CPU访问内存的最自然方式就是使用物理地址,我们把这种方式称为物理寻址(黑体字是原话),本书P560页有个示意图,访问地址4开始的4字节字.假设地址4的物理地址是0x12345678,那么用汇编语言是这样写的:
//汇编代码
movel 0x12345678,%eax //传递4字节数据进CPU寄存器%eax,假设是32位系统
早期的PC使用物理寻址,而且诸如数字信号处理器、嵌入式微控制器以及Cray超级计算机这样的系统仍然继续使用这种寻址方式.(黑体字是原话)
----解读:物理寻址在超级计算机中仍然使用,说明他可能并不需要执行多任务.
2>虚拟寻址
使用虚拟寻址,CPU通过生成一个虚拟地址(Virtual Address,VA)来访问主存,这个虚拟地址在被送到内存之前先转换成适当的物理地址.地址翻译需要CPU硬件和操作系统之间的紧密合作.CPU芯片上叫做内存管理单元MMU (黑体字是原话)
----解读:CPU由向物理地址要数据转而向虚拟地址要数据.虚拟地址由MMU翻译成物理地址,两者之间存在对应关系.见本书P560
回顾CPU的工作过程:
1)CPU以进程为单位执行代码,代码编译后是机器指令
2)机器指令在操作数据,指令本身也是数据.数据以地址形式存在.
3)CPU向存储索要数据,并将处理好的数据发回存储.
白话:CPU对寄存器说,我要干活,请把活路儿(指令)给我.如果是物理寻址,寄存器找物理地址(按照存储层次,从高速缓存开始直到内存);如果是虚拟寻址,寄存器把虚拟地址发给MMU,后者找到对应的物理地址给他.
虚拟地址的优势在于方便数据(地址)的管理:每个进程都按照相同的虚拟地址排布,例如代码地址从0x400000000开始.其余部分类似规律,参考本书P510图"进程地址空间",这是虚拟内存一致性的体现.程序员在编程时每个程序的数据都按照此种方法去申请地址,执行时由调度算法确定.
地址空间
一个地址空间的大小是由表示最大地址所需要的位数来描述的(黑体字是原话)
----解读:这算是计算机里很基础的一个知识点了.比如n位系统,最大寻址能力2的n次方.他可以表示2的n次方个数据,由于编号从0开始,所以表示范围:0~2的n次方-1.例如有一个数组a[n],a[0]表示该数组中第一个元素,最后一个元素用a[n-1]表示.还有一点,n位系统每个数据最大表示值也是2的n次方-1.
======================内容分割线上=========================================
题外话:笔者觉得在任意时候,把"地址"理解为"数据"都是可以的,利于培养一种感觉.
例如:1.一个32位地址,他表示一个4字节的数据.
2.一张桌面有100万个像素点(分辨率大约720P),每个点16位(2字节)色彩,则需要2X3X100万=600万个字节,即一幅图占6MB空间.刷新率100hz,则6X100=600MB,显存空间600MB.
======================内容分割线下=========================================
允许每个数据对象有多个独立的地址,其中每个地址都选自一个不同的地址空间.这就是虚拟内存的基本思想.主存中的每字节都有一个选自虚拟地址空间的虚拟地址和一个选自物理地址空间的物理地址. (黑体字是原话)
----解读:每个数据都有物理地址空间和虚拟地址空间,他们是在数据大小方面是对应关系.但有共享数据,即一个物理地址可以对应多个虚拟地址.
缓存概述与内容
缓存是本书第六章内容。他的大概意思是这样的:计算机所有数据都要由CPU寄存器处理,开始时寄存器直接向内存(主存)寻址,速度比较慢。后来计算机在设计时引入了多层次存储机制,在CPU寄存器往下设置了一,二,三级(也不一定就限定三级)缓存,再到主存。上层数据是下层的子集,上层容量小,速度快,下层容量大,速度慢。这样做的目的是:越常用的数据越靠近寄存器,节省调用数据时间。
======================内容分割线上=========================================
以下内容属于发散思考,不做完全正确的保证.
缓存的内容有什么?以一级缓存为例
说明:一级缓存L1向上一级的缓存是CPU寄存器. 本书第三章内容中,当进程切换时有寄存器压栈,上下文切换的操作.所以可预见的相关数据被放入一级缓存中.当进程切换回来时,相关数据将被再次使用.
而其他非一级缓存内容可能只有进程指令和进程操作数,不包含进程上下文了.包括其他进程,例如进程2,进程3到进程n的内容.
指令中的操作数是虚拟地址---包含在右边第一列的每一项当中,即:指令=指令码地址+操作数地址,操作数地址.举例:moveq 0x1000,%rax;而内存管理单元(MMU)负责把0x1000翻译成物理地址,从内存中取出数据放入缓存的操作数序列---右边第二列.CPU运行时从缓存的操作数序列中取出地址(数据)进行计算.所以CPU还需要维护一个地址偏移量.他们的关系是:物理地址→虚拟地址→缓存中的地址.
---对于写应用代码的程序员来说,这部分属于超纲了,所以不必深究,设计操作系统的人才会去考虑这个问题.发散思维是为了保持思考.
======================内容分割线下=========================================
虚拟内存作为缓存工具
本书P561:虚拟内存被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组.每字节都有一个唯一的虚拟地址,作为到数组的索引.(黑体字是原话)
----解读:缓存的数据单元大小是4kb~2Mb.虚拟地址和物理地址存在对应关系.笔者认为原书在这里表述错误.每段虚拟内存都有唯一的虚拟地址,作为到数组的索引.缓存的大小是约定好的.假设物理地址是0x10000000,对应的虚拟地址是0x20000000,那么0x10001000和0x20001000(十进制相差4096,也就是4k个字节).他们之间的数据部分是对应的.
这里有一个小细节:是否需要数据的4k对齐.复习数据对齐的概念:计算机以字长为单位寻址.例如32位机,每两个数据(地址)之间相差4,以0x00,0x04,0x08,0x0c为末尾寻址.所以在<C Prime Plus>那本书里有讲过数据对齐的概念.即设计的数据类型,大小是4字节的整数倍(32位机),方便数据的查找.那么,程序运行的每个场景所需要的数据,是否也应该保证4k字节的对齐?同时如果不能对齐,对程序的影响大不大?试想差别一个页帧,4k数据在大型系统中几乎没影响,如果是资源比较少的系统中可能会需要考虑.但具体情况笔者不清楚,可以作为以后分析程序的一个点去关注
虚拟内存按是否缓存状态分为:未分配,已缓存,未缓存这三种.他的含义是以状态为依据调配数据,很好理解.
虚拟页很大的原因
本书P562 硬盘缓存到内存中的速度很慢,所以缓存的数据单元---虚拟页的大小做得比较大.一般是4Kb~2Mb
虚拟内存的实现基础--数据的访问机制
在32位机时代,有个说法:最大寻址能力4GB.所以物理内存4GB是极限,超过部分起不到作用.事实真的是这样吗?准确说法是:32位机访问的数据块大小最大是4GB.因为有个叫做"指针"的东西可以对数据进行扩展.用一个指针指向≤4GB的数据块,则把一个4GB的数据"浓缩"成一个4B(字节)的数据(指针).访问数据时先通过指针,再进行寻址.理论上8位机能访问的数据,也可以是无限的.所以,数据的访问机制,支持了操作系统可以对所有数据统一编址,统一管理.
笔者记得winXP系统的文件大小有4GB限制,原因可能是操作系统不支持用指针扩展数据访问.
======================内容分割线上=========================================
MMU(内存管理单元)和缓存原理
编译后的程序,是一些代码文件(机器指令),以及代码中需要的数据文件(数据).他们被放在硬盘中.操作系统会对其进行编址,这个地址就是虚拟地址.
当开始运行程序时,代码文件和数据文件会被划分为4KB大小的数据块,调入内存,并逐级向上进入CPU寄存器,交由CPU处理.由于数据块大小固定,所以MMU只需要记录首地址即可.
---说明:图中地址属假设.
每个地址间相差0x1000,即2的12次方个字节,4KB字节大小数据.
如果代码有需要使用虚拟地址为0x10000500的数据,需指针指向0x60000000的地址(一级缓存中的地址),再偏移0x00000500个单元,再取出数据.
页表
页表在对每级数据缓存进行管理,监督缓存的结果,如果没缓存到位调用内核程序传递数据,也就是使用moveq指令.笔者认为除了DRAM动态缓存(从硬盘调入主存)有页表,其他SRAM也会有页表.本书中没说.
本书中有个页表工作示意图,提取了MMU示意图的一部分来工作.理解了MMU的原理,页表就容易理解了.
缓存内容补充
按照程序设计的思路,内存中应划分静态存储区,动态分配存储区,临时存储区.他们各司其职.所以缓存示意图(本贴第一张图)并不完善,每个进程中还应有这些区域划分.而缓存容量是有限的,原则是当前使用越频繁的数据,越靠近CPU寄存器.所以缓存的替换算法,应该是比较复杂的.如何在有限区间内合理分配每个数据块的大小,也如上所述,这些是写操作系统的人和设计芯片的工程师考虑的,写软件的只是稍作思考.
分割线内的内容属于发散思考,不保证完全准确
======================内容分割线下=========================================
时间局部性和抖动
使用过老旧电脑的人会有深刻的体会:内存小了,CPU慢了,硬盘指示灯一直在闪烁,画面几乎静止不动.这就是抖动.原理是硬盘和内存一直在交换数据,CPU几乎腾不出空来计算.
小结
虚拟内存好处有以下两点:
1>统一数据管理.所有的代码,以及代码中要求的数据,都是操作系统能访问和控制的地址.
2>灵活数据使用.只有程序被运行时,数据才会被调入内存,交给CPU计算.MMU表内,虚拟地址和物理地址两项不会变,但主存,SRAM各个缓存中的地址是随机的.
题外话:这部分内容属于底层比较难的,笔者的角度好像一个小孩子看见精密的一台设备开始各种猜想,只是做个浅见.