赞
踩
物理寻址:CPU访问存储器的最原始方法就是直接用物理地址(Physical Address, 可简称PA)。物理地址是唯一的。
虚拟寻址:CPU通过生成一个虚拟的地址来访问内存,在访问前会把虚拟地址转化为物理地址。虚拟地址(virtual Address, 可简称VA)。
MMU:它是memory manage unit
的缩写,内存管理单元。内存管理单元是CPU芯片上的硬件,它的作用是利用存放在内存中的表将虚拟地址转变成物理地址,这个转变的步骤被称为地址翻译。
我们平常写程序所看到的地址都是虚拟地址。
验证:
//mycode.c 1 # include <stdio.h> 2 # include <unistd.h> 3 int main(void) 4 { 5 int id; 6 int val = 1314; 7 id = fork(); 8 while(1) 9 { 10 if(id == 0) 11 { 12 //child 13 printf("i am child, val=%d, my val_address: %p.\n",val , &val); 14 sleep(1); 15 } 16 else{ 17 //father 18 val = 520; //将val的值修改成520 19 printf("i am father, val=%d, my val_address: %p.\n",val, &val); 20 sleep(1); 21 } 22 sleep(1); 23 } 24 return 0; 25 }
运行以上程序。
//提取内容
i am father, val=520, my val_address: 0x7ffdca7cf3d8.
i am child, val=1314, my val_address: 0x7ffdca7cf3d8.
惊奇地发现,地址都是0x7ffdca7cf3d8
,而地址中的内容一个是520,一个是1314,如果是同一个物理地址,值为什么会不一样!这说明我们看到的是虚拟地址,这些虚拟地址映射到了不同的物理地址。
我在文章里说的“内存”是物理内存
地址空间:非负整数地址的有序集合。如果地址空间中的地址是连续的,则它是一个线性地址空间。
地址空间有:虚拟地址空间和物理地址空间。虚拟地址空间实际上是把外部存储器的磁盘中的部分当作了内存,所以也叫虚拟内存,因为它不是真正的内存。
地址空间大小的描述:地址空间内包含有2^n个地址,则称为n位地址空间。
接下来的讨论将假设为线性的地址空间。
这样就像把地址空间划分成了一块一块的样子。
虚拟页的大小和物理页的大小讲究对齐原则。
虚拟页面有以下几种状况。
缓存似乎有点抽象,映射要好理解得多!
页表:是一个页表条目(PTE,Page Table Entry的缩写)的数组,存放在物理存储器中。内存管理单元通过页表将虚拟页映射到物理页,将虚拟地址翻译成物理地址。
虚拟页号当作数组下标,也就是虚拟页号当作索引,通过虚拟页号就可以找到对应的页表条目。
1】虚拟页0和3还未被分配。
2】虚拟页1、2、4、7已映射到物理内存。
3】虚拟页5、6已被分配,但是还没有映射到物理内存。
有效位用于判断该虚拟页是否被映射到了物理内存中。CPU如果访问已经分配,但是还没有被映射到物理内存的虚拟页,这种情况称为缺页。假设现在CPU要访问vp5中的数据,当MMU内存管理单元从物理存储器中读PTE 5,它的有效位显示这个虚拟页还没有被映射,就会触发缺页异常,缺页异常会调用缺页异常处理程序。
这个过程暂时停止访问,转而去处理缺页,所以这叫缺页中断。
缺页中断时,操作系统需要选择内存里的一个页面,牺牲掉它的位置,让给要调入的虚拟页面。
对于这个要牺牲掉的牺牲页,如果它在内存里的时候被修改过了,就需要把它写回磁盘上,更新这个页面在磁盘上的副本。如果没有修改过,就不需要写回去。你用word写过一些东西吧,当你在写的时候,这个数据就被加载进了内存里,如果你忘记保存了,那么下一次可能数据就丢失了,这就是因为页面被你修改了,但是你还没有更新磁盘上的副本,那么是不能永久保存的。
那么操作系统会选择牺牲掉哪一个页面呢?
发生缺页中断的时候,操作系统也许会随机的选择一个牺牲页来置换,但是这样并不好!在虚拟内存和内存之间传送页,这个动作称为页面调度,或者页面置换 ,还可以称为交换。针对不同的优化方向,衍生出了许多地页面调度的策略,这能够尽可能地达到最优性能。
页面调度的策略就是页面调度算法,常见的页面调度算法:
- | - |
---|---|
最优页面调度 | 最近未使用页面调度(NRU算法) |
先进先出页面调度(FIFO算法) | 第二次机会页面调度 |
时钟页面调度 | 最近最少使用页面调度(LRU算法) |
工作集页面调度 | 工作集时钟页面调度 |
最近不经常使用页面调度(NFU算法) | …… |
上面所述的页表是简化的版本,实际上,页表条目(PTE)中不只有有效位,还有许多其他的标志位。
保护位:PTE增加了保护位起到了保护的作用,保护位实际上就是做了一些权限,限制这个PTE对应的页面是否可以读、写、执行。不然你以为被const
修饰的内容为什么能做到只读的呢?这里只是简单地举个例子。
修改位:用于判断这个PTE所对应的页面是否被修改过,缺页中断要进行页面换出时,这是非常有用的,如果牺牲页面驻留在内存时被修改过了,那么就必须把该页面写回磁盘,目的是更新磁盘上该页面的副本。修改位也称为“脏位”,这个页面被修改了——>“这个页面脏了”
访问位:在发生缺页中断时,操作系统可以借助访问位的值来选择牺牲页。
高速缓存禁止位:顾名思义,这个标志位可以禁止该PTE对应的页面进行高速缓存。
sup位:这个位用于表示是否需要在内核模式(内核态)才能访问页面。
MMU是如何利用页表实现地址翻译的?
CPU中有一个寄存器,页表基址寄存器(PTBR),这个寄存器指向当前页表的首地址。而虚拟地址显示了虚拟页号(VPN)和虚拟页偏移量(VPO)。MMU通过虚拟页号找到对应的页表条目(PTE),因为虚拟页和物理页讲究对齐原则,所以虚拟页的偏移量和该物理页面的偏移量是一样的将页表条目(PTE)里的物理页号和物理页的偏移量串联起来,得到对应的物理地址。
上面所描述的页表实际上是慢表!
什么?慢表?难不成还有快表吗!没错,页表有慢表和快表。
之所以说前面描述的存储在物理内存中的页表是慢表,是因为有了分页机制后,当CPU产生一个虚拟地址时,内存管理单元MMU就需要去内存访问一次PTE,后面还要访问物理内存中的物理页面,至少要访问两次物理内存!导致现在至少访问两次物理内存才相当于原本的访问一次物理内存,那么还会有人需要分页机制吗?
实际上很多的程序总是反复地读取少量的页面,其他的页面很少被访问,根据这个突破点,在内存管理单元MMU中设置了一个硬件设备——>翻译后备缓冲器(Translation Lookaside Buffer,简称TLB)。 也可以称为快表或者相联存储器。
快表实际上就是一个比较小的缓存,每个缓存行里保存着一个PTE
当虚拟地址空间非常大的时候,对应的页表也就非常地大,比物理内存还要大,这是万万不行的!所以要想办法 压缩页表。
压缩页表的最常用的办法就是划分层次结构,划分出层次结构,那么就衍生出了多级页表。
好比以前没有网络的时候,学校要面对全校师生个人召开重要的会议,找学校里的一个人,但是学校的人太多了,常用的方法就是划分出层次来分批召开会议,领导先给各班的老师开会传达内容,然后各班老师来给寝室长开会传达内容,寝室长给其他人员开会传达内容,最终就可以找到这个人。
多级页表类似于这样的机制。
多级页表可以避免把全部的页表一直驻留在物理内存中,特别是一些不用的页表,免得浪费物理内存。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。