0%

操作系统内存管理

为了让不同的应用程序能够既高效又安全的共同使用内存,现代操作系统的普遍做法是在应用程序和物理内存之间加入一个新的抽象:虚拟内存。应用程序面向虚拟内存进行编写而不是面向物理内存进行编写,应用程序在运行时只能够使用虚拟内存,操作系统负责虚拟内存和物理内存之间的映射,CPU负责将虚拟内存翻译为物理内存。

CPU中的组件内存管理单元(MMU)负责虚拟地址到物理地址的转换。程序在CPU上运行时,它使用的虚拟地址都会由MMU进行翻译。当需要访问物理内存设备的时候,MMU翻译出的物理地址信息将会通过总线传递到相应的物理内存设备中去,从而完成相对应的物理内存读写请求。

分段与分页机制

MMU将虚拟地址转换为物理地址的主要机制有两种,分别为分段机制和分页机制

分段

在分段机制下,操作系统以段为的形式管理物理内存。当CPU访问虚拟内存地址空间中的某一段时,MMU会通过查询段表得到该段对应的物理内存区域。虚拟地址由两个部分组成,第一个部分表示段号,标识着该虚拟地址属于整个虚拟地址空间的哪一段;第二部分表示段内地址,即相对于该段起始地址的偏移量。在段表中会存放着一个虚拟地址空间中每一个分段的信息,包括段起始地址和段长。在翻译虚拟地址的过程之中,MMU首先会通过段表基址寄存器来找到段表的位置,结合代翻译虚拟地址中的段号找到对应段的信息,然后取出该段的起始地址,加上段内地址就能得到最终的物理地址。段表中还存有段长信息来检查虚拟地址是否超过合法范围。

分段机制

在分段机制下,虚拟地址和物理地址都以段为单位进行分配。这种分配方式会导致物理内存的外部碎片,在段与段之间留下碎片空间,从而造成物理资源利用率的降低。例如一个3GB的内存被分为3段进行分配,第一段为0-1GB,第二段为1-2GB,第三段为2-3GB。如果第一段和第三段被释放,之后又分配一个2GB的段会出现分配失败的情况。

分页

分页机制时现代操作系统广泛采用的机制。其思想是将应用程序的虚拟地址空间和物理内存都划分为连续的等长的虚拟页(分段机制下位不同长度的段),由操作系统为每个应用程序构造虚拟内存到物理页的映射关系表(即页表)。虚拟地址由虚拟页号和页内偏移量两个部分组成。在翻译过程中,MMU首先会解析得到虚拟地址的虚拟页号,并通过虚拟页号去页表(存放于页表基地址寄存器)中取出对应的物理页号,然后与虚拟地址中的页内偏移量相加得到最终的物理地址。

多级页表

页表负责记录虚拟页到物理页的映射关系。对于63位的虚拟地址空间,假设页的大小为4KB,页表中每一项大小为8字节,那么一张页表的大小为2^64/4*8字节大小即32PB。为了对页表进行压缩,操作系统引入了多级页表的结构,用来满足虚拟内存在高效性上的要求。

在使用多级页表的时候,一个虚拟地址仍然包括虚拟页号以及业内偏移量,其中虚拟页号被划分为了多个部分,虚拟页号i对应着该虚拟地址在第i级页表中的索引。当任意一级的页表中的某一个条目为空时,该条目下一级的页表就不需要存在,因此多级页表的设计极大地减少了页表占用的空间大小。

以五层页表为例,通常在当MMU翻译一个虚拟地址的时候,会先根据页表基地址寄存器中的物理地址找到第0级页表页,将第0级的虚拟页号作为页表项索引,读取对应的页表项,该页表项中存储着下一级的页表项的物理地址,按照类似的方式依次读取第2级页表,第3级页表。MMU将在第3级页表项之中的页表项里面找到该虚拟地址对应的物理页号,结合虚拟地址中的业内偏移量获取最终的物理地址。

TLB

多级页表能够压缩页表大小,但是会导致页表翻译时间的增加。为了减少地址翻译的访存次数,MMU引入了TLB机制来加速地址翻译的过程。在TLB之中缓存了虚拟页号到物理页号的映射关系,可以简单地将TLB简化成为一个键为虚拟页号值为物理页号的哈希表。

换页与缺页异常

换页机制是当物理内容容量不够的时候,操作系统将物理页的数据写入到磁盘之中,然后回收这些物理页并继续使用。当应用程序访问已分配但是未映射到物理内存的虚拟页时,就会触发缺页异常。此时操作系统会找到空闲的物理页,将之前写到磁盘上的数据重新加载到物理页之中,并在页表之中填写虚拟地址到这一物理页的映射,之后CPU回到发生缺页中断的地方继续运行。

页替换策略

当分配物理页时,如果空闲的物理页已经用完,操作系统将会根据页替换策略分配一个物理页换出到磁盘中以让出空间。

OPT策略在选择被换出的页时,优先选择未来最长事件不会再访问的页。这种策略是最优的页替换策略,但是在实际中因为页访问策略取决于应用程序,操作系统无法预知应用程序的行为,所以很难进行实现。

FIFO策略优先选择最先换入的页进行换出,是最简单的页替换策略之一,因为简单其时间开销很低,但是在实际使用中常常表现不佳。

LRU策略优先选择最久未被访问的页。在实际实现中,需要精确的记录时间信息记录CPU访问了哪些物理页,其实现开销比较大。

时钟算法策略将换入物理内存的页号排成一个时钟的形状。该时钟有一个手臂只相信换入内存的后一个,同时为每一个页号维护一个访问标志位,每次需要选择换出页号时,该算法从针臂所指的页号开始检查,如果当前页号的访问位没有色湖之,就将该页替换,否则将访问位清空。如此重复直到找到一个访问位未被置上的页号。

工作集模型

如果选择的页替换算法与真实的工作负载不匹配,那么会导致出现颠簸现象,造成性能损失。

工作集模型能够有效的避免颠簸现象的发生。工作集的定义是一个应用程序在时刻t的工作集W为它在时间区间[t-x,t]使用的内存页集合,也视为它在下一段x时间内会访问的内存页集合。该模型将应用程序的工作集要么全部都在物理内存之中,要么全部被换出,从而减少应用程序工作时发生换页的次数。

虚拟内存

虚拟内存使得应用程序能够拥有独立且连续的内存空间。其功能包括共享内存,写时拷贝,内存去重,内存压缩,内存大页等等。

共享内存允许同一个物理页在不同的应用程序之间共享,且能够同时看到对方修改的内容。共享内存的作用是让不同的应用程序相互通信和传递数据。

写时拷贝允许多个应用程序以只读的方式共享同一段物理内存。一旦某一个应用程序对该内存进行修改,就会发生缺页异常,操作系统会将对应的物理页重新拷贝一份重新映射给触发异常的应用程序,此后再恢复应用程序的执行。

基于写时拷贝技术,操作系统进一步设计了内存去重功能,在内存中扫描具有相同内容的物理页,找到映射到这些物理页的虚拟页,然后只保留其中一个物理页,将其他虚拟页以写时拷贝的方式映射到这个物理页。在Linux系统中该功能称为KSM。

当内存资源不足时,操作系统会使用一些最近不太会使用的内存页进行压缩,从而释放出更多的空闲内存。当应用程序需要进行访问的时候操作系统则将其解压,Linux中的zswap机制就使用到了内存压缩技术。