Skip to content

《面渣逆袭》操作系统 篇 · 第 4/6 章。原版 PDF(下载 / 打印)

什么是虚拟内存? ​

我们实际的物理内存主要是主存,但是物理主存空间有限,所以一般现代操作系统都会想办法把一部分内存块放到磁盘中,用到的时候再装入主存,但是对用户程序而言,是不需要注意实际的物理内存的,为什么呢?因为有虚拟内存的机制。

简单说,虚拟内存是操作系统提供的一种机制,将不同进程的虚拟地址和不同内存的物理地址映射起

来。​

每个进程都有自己独立的地址空间,再由操作系统映射到到实际的物理内存。

于是,这里就引出了两种地址的概念:

程序所使用的内存地址叫做虚拟内存地址​(Vi rtualMemoryAddress)

实际存在硬件里面的空间地址叫物理内存地址​(PhysicalMemoryAddress)。

配图

什么是内存分段? ​

程序是由若干个逻辑分段组成的,如可由代码分段、数据分段、栈段、堆段组成。不同的段是有不同的属性的,所以就用分段(Segmentation)的形式把这些段分离出来。

分段机制下的虚拟地址由两部分组成,​段号和段内偏移量​。

虚拟地址和物理地址通过段表映射,段表主要包括段号​、​段的界限​。

配图

我们来看一个映射,虚拟地址:段3、段偏移量5 00 ----> 段基地址7 000+ 段偏移量5 00----> 物理地址:7 500。

配图

什么是内存分页? ​

分⻚是把整个虚拟和物理内存空间切成一段段固定尺寸的大小​。这样一个连续并且尺寸固定的内存空间,我们叫⻚(Page)。在 Linux 下,每一⻚的大小为 4KB。

访问分页系统中内存数据需要两次的内存访问:一次是从内存中访问页表,从中找到指定的物理页号,加上页内偏移得到实际物理地址,第二次就是根据第一次得到的物理地址访问内存取出数据。

配图

多级页表知道吗? ​

操作系统可能会有非常多进程,如果只是使用简单分页,可能导致的后果就是页表变得非常庞大。

所以,引入了多级页表的解决方案。

所谓的多级页表,就是把我们原来的单级页表再次分页,这里利用了局部性原理​,除了顶级页表,其它级别的页表一来可以在需要的时候才被创建,二来内存紧张的时候还可以被置换到磁盘中。

配图

什么是块表? ​

同样利用了局部性原理​,即在一段时间内,整个程序的执行仅限于程序中的某一部分。相应地,执行所访问的存储空间也局限于某个内存区域。

利用这一特性,把最常访问的几个⻚表项存储到访问速度更快的硬件,于是计算机科学家们,就在

CPU 芯片中,加入了一个专⻔存放程序最常访问的⻚表项的 Cache,这个 Cache 就是 TLB (Tr anslationLookasideBuffer),通常称为⻚表缓存、转址旁路缓存、快表等。

配图

分页和分段有什么区别? ​

段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的。

段的大小不固定,有它所完成的功能决定;页的大小固定,由系统决定段向用户提供二维地址空间;页向用户提供的是一维地址空间段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制。

什么是交换空间? ​

操作系统把物理内存( PhysicalRAM) 分成一块一块的小内存,每一块内存被称为页( page)。当内存资源不足时,Linux 把某些页的内容转移至磁盘上的一块空间上,以释放内存空间。磁盘上的那块空间叫做交换空间( swapspace), 而这一过程被称为交换( swapping)。物理内存和交换空间的总容量就是虚拟内存的可用容量。

用途:

物理内存不足时一些不常用的页可以被交换出去,腾给系统。

程序启动时很多内存页被用来初始化,之后便不再需要,可以交换出去。

页面置换算法有哪些? ​

在分页系统里,一个虚拟的页面可能在主存里,也可能在磁盘中,如果CPU 发现虚拟地址对应的物理页不在主存里,就会产生一个缺页中断,然后从磁盘中把该页调入主存中。

如果内存里没有空间,就需要从主存里选择一个页面来置换。

常见的页面置换算法:

配图

最佳⻚面置换算法(OPT)​

最佳⻚面置换算法是一个理想的算法,基本思路是,​置换在未来最⻓时间不访问的⻚面​。

所以,该算法实现需要计算内存中每个逻辑⻚面的下一次访问时间,然后比较,选择未来最⻓时间不访问的⻚面。

但这个算法是无法实现的,因为当缺页中断发生时,操作系统无法知道各个页面下一次将在什么时候被访问。

先进先出置换算法(FIFO)​

既然我们无法预知⻚面在下一次访问前所需的等待时间,那可以选择在内存驻留时间很⻓的⻚面进行中

置换​,这个就是「先进先出置换」算法的思想。

FIFO 的实现机制是使用链表将所有在内存的页面按照进入时间的早晚链接起来,然后每次置换链表头上的页面就行了,新加进来的页面则挂在链表的末端。

配图

最近最久未使用的置换算法(LRU)​

最近最久未使用(LRU)的置换算法的基本思路是,发生缺⻚时,​选择最⻓时间没有被访问的⻚面进行

置换​,也就是说,该算法假设已经很久没有使用的⻚面很有可能在未来较⻓的一段时间内仍然不会被使用。

这种算法近似最优置换算法,最优置换算法是通过「未来」的使用情况来推测要淘汰的⻚面,而 LRU则是通过历史的使用情况来推测要淘汰的⻚面。

LRU 在理论上是可以实现的,但代价很高。为了完全实现 LRU,需要在内存中维护一个所有⻚面的链表,最近最多使用的⻚面在表头,最近最少使用的⻚面在表尾。

配图

困难的是,在每次访问内存时都必须要更新整个链表。在链表中找到一个⻚面,删除它,然后把它移动到表头是一个非常费时的操作。

所以,LRU 虽然看上去不错,但是由于开销比较大,实际应用中比较少使用。

时钟页面置换算法

这个算法的思路是,把所有的⻚面都保存在一个类似钟面的环形链表中,一个表针指向最老的⻚面。

配图

当发生缺⻚中断时,算法首先检查表针指向的⻚面:

如果它的访问位位是 0 就淘汰该⻚面,并把新的⻚面插入这个位置,然后把表针前移一个位置;

如果访问位是 1 就清除访问位,并把表针前移一个位置,重复这个过程直到找到了一个访问位为 0 的⻚面为止;

最不常用置换算法

最不常用算法(LFU),​当发生缺⻚中断时,选择访问次数最少的那个⻚面,将其置换​。

它的实现方式是,对每个⻚面设置一个「访问计数器」,每当一个⻚面被访问时,该⻚面的访问计数器就累加 1。在发生缺⻚中断时,淘汰计数器值最小的那个⻚面。

本文整理自三分恶《面渣逆袭》系列的公开内容,仅供个人学习使用

本站仅供个人学习使用,请勿外传