操作系统虚拟内存
虚拟内存
虚拟内存的存在是为了运行比物理内存还大的程序,可以让系统看上去比实际物理空间大小大得多,并为多道程序的执行创造了条件。
明确一个概念:内存中的每一个存储单元都必须有确切的地址,而例如对32位机来说,能发出的地址数目就是2^32=4G,这也被称为处理器的寻址能力。因此机器内存的大小也应该是和处理器的最大寻址能力对应的。
但现实往往不是这样的,导致了大量寻址能力的浪费。但我们可以明确一点:程序总是被逐断运行的,一段时间内会稳定运行在某一段程序中。
因此一种做法是:把要运行的那一段程序从辅存(磁盘等外部存储设备)中复制出来,其余仍然留在辅存。当要运行下一段程序时,就把内存中的上一段程序换回到磁盘中。这也就让内存看起来变大了,这个存储空间也被叫做虚拟内存空间。这个虚拟内存空间是右寻址能力决定的。
这也就是说,一个程序被执行,需要执行两次映射,第一次映射到虚拟内存,第二次映射到物理内存。负责这个任务的硬件部分被称为存储管理单元(MMU),软件部分被称为内存管理模块。
内存管理模块记录着一个虚拟地址/物理地址映射表,作为MMU转换的依据。
虚拟内存技术
但以存储单元来管理显然不太现实,因此Linux把虚存空间分成若干个大小相等的存储分区,称为页。为了换入换出方便,物理内存也应该按照这种格式,物理内存的分块被称为页框。页与页框是Linux实现虚拟内存的基础。
物理内存地址,高位被称为页框码,低位被称为页框偏移量。
虚拟内存地址,低位被称为页码,低位被称为页内偏移量。
同时,应该还需要记录一个页表。在把一个页映射到某个页框的同时,就应该把对应的映射关系填入页表。
在地址转换的过程中,偏移量是不会变的。(先留个坑,再待探究)
请页与交换
虚存页面到物理页框的映射称为页面的加载。
当处理器试图访问一个虚拟内存页面时,先去查询是否已经映射到物理页框中,并记录到页表中。
- 如果在,MMU(虚拟内存管理机制)会把页面转换成页框码,物理地址=页框码*页面大小+页偏移量,然后访问物理内存。
- 如果不在,则发生页面访问错误,系统将判断该地址是否为有效地址。
- 如果是有效地址,就从虚拟地址就将该地址指向的页面读入到内存的一个空闲页框中,并在页表上添加相关项
- 如果是无效地址,则操作系统将终止本次访问
如果没有空闲物理页框了,就将执行缺页置换机制:
- FIFO,先进先出
- LFU,最不经常访问
- LRU,最近一段时间最久没有访问
为了更加公平,Linux采用LRU算法,然后将页面移除,加入新的页面。
快表
访问虚拟内存时,每次都去页表里面找是很浪费时间的。但是人们发现,一旦访问了某个页,就会一段时间稳定工作在这个页上。于是系统提供了一个刚好能容纳一个页表的硬件寄存器,这样每次都先去寄存器中访问,速度就会快很多。我们称之为快表。
使用快表之后的地址转换流程是这样的:
- 根据虚拟地址中的页号查快表;
- 如果该页在快表中,直接从快表中读取相应的物理地址;
- 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
- 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。
可以发现,虚拟内存不可能仅仅只通过软件来完成,必须配备一些硬件来承担一部分任务。
多级页表
一个程序在运行时,页表也要放在内存中。如果虚拟空间太大,就会导致页表太大,不可能说一次性全放到内存中。
所以应该再对页表进行分页存储,只把需要的页放到内存中。我们对页表建一个目录一样的东西,对应页表分页后的每个首地址,就可以进行查找。
当然,如果还是很大,就可以循环套娃,多建几级。
为了通用,Linux采用三级页表结构:页目录,中间页目录和页表。
分页和分段的异同
共同点:都是为了提高内存利用率,减少碎片。页和段在内存中是连续的。
不同点:页的大小是固定的,取决于操作系统;段的大小是不固定的,取决于运行的程序。
局部性原理
时间局部性:如果程序中的某条指令一旦执行,不久以后该指令可能再次执行;如果某数据被访问过,不久以后该数据可能再次被访问。产生时间局部性的典型原因,是由于在程序中存在着大量的循环操作。
空间局部性 :一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围之内,这是因为指令通常是顺序存放、顺序执行的,数据也一般是以向量、数组、表等形式簇聚存储的。
补充
- 32位和64位的区别?
CPU是通过物理总线访问内存,32位机就是32条总线,每条总线有高低两种电位0和1,可访问的最大地址就是2^32;64位机并没有64条总线,毕竟那真的太大了,因此最大内存要受限于操作系统。 - 虚拟内存更容易实现内存共享:每个进程都有自己的进程控制块和地址空间,以及与之对应的页表。两个不同的虚拟地址通过页表映射到物理空间的同一区域,即实现了内存共享。