1. 什么是虚拟内存?解决了什么问题?

虚拟内存是操作系统内存管理的一种技术,每个进程启动时,操作系统会提供一个独立的虚拟地址空间,这个地址空间是连续的,进程可以很方便的访问内存,这里的内存指的是访问虚拟内存。虚拟内存的目的,一是方便进程进行内存的访问,二是可以使有限的物理内存运行一个比它大很多的程序。

虚拟内存的基本思想:每个程序拥有自己的地址空间,这个空间被分割成很多块,每块称为一页,每一页地址都是连续的地址范围。这些页被映射到物理内存,但不要求是连续的物理内存,也不需要所有的页都映射到物理内存,而是按需分配,在程序片段需要分配内存时由硬件执行映射(通常是 MMU),调入内存中执行。

2. 说说分页和分段的机制?

分页是实现虚拟内存的技术,虚拟内存按照固定的大小分为页面,物理内存也会按照固定的大小分成页框,页面和页框大小通常是一样的,一般是 4KB,页面和页框可以实现一对一的映射。分页是一维的,主要是为了获得更大的线性地址空间。但是一个地址空间可能存在很多个表,表的数据大小是动态增长的,由于多个表都在一维空间中,有可能导致一个表的数据覆盖了另一个表。

分段是把虚拟内存划分为多个独立的地址空间,每个地址空间可以动态增长,互不影响。每个段可以单独进行控制,有助于保护和共享。

3. 页表的作用?为什么引入多级页表?

页表实现了虚拟内存到物理内存的映射,当访问一个虚拟内存页面时,页面的虚拟地址将作为一个索引指向页表,如果页表中存在对应物理内存的映射,则直接返回物理内存的地址,否则将引发一个缺页异常,从而陷入到内核中分配物理内存,返回对应的物理地址,然后更新页表。

为了加快虚拟地址到物理地址的转换,多数系统会引入一个转换检测缓冲区(TLB)的设备,通常又称为快表,当请求访问一个虚拟地址时,处理器检查是否缓存了该虚拟地址的映射,如果命中则直接返回物理地址,否则就通过页表搜索对应的物理地址。

由于虚拟内存通常比较大(32 位系统通常是 4G),要实现整个地址空间的映射,需要非常大的页表。解决的办法是引入多级页表,只将那些用到的页面装载进来,因此,多级页表可以大大节约地址转换所需要的的空间。

4. 页面置换算法有哪几种?

当访问的页面不在内存中时,会发生一个缺页异常,操作系统必须将该页换出内存,如果此时内存已满,则操作系统必须将其中一个页面换出,放到 swap 交换区中,为当前访问的页面腾出空间,这个过程称为页面置换。操作系统提供了多种页面置换算法:

最优页面置换算法

选择一个将来最长时间不会被访问的页面换出。这样可以保证将来最低的缺页率。这是一种理论上的算法,因为无法知道哪个页面是将来最长时间都不会被访问的。

最近未使用页面置换算法 (NRU)

为每个页面设两个状态位:被访问时设置为 R=1 位,页面被修改时,设置为 M=1 位。当启动一个进程时,所有页面都被初始化为 R=0,M=0。其中 R 位会被定时的清 0,以此区分最近被访问的页面和没有被访问的页面。

于是所有页面可以分为以下 4 类:

0 类:R=0,M=0;

1 类:R=0,M=1;

2 类:R=1,M=0;

3 类:R=1,M=1;

当发生缺页中断时,NRU 算法随机地从类编号最小的非空类中挑选一个页面将它换出(挑选优先级:1 类 > 2 类 > 3 类)。

最近最少未使用(LRU)页面置换算法

在内存中维护一个所有页面的单链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。

因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。

先进先出(FIFO)页面置换算法

维护一个链表,最先进入的页面放在表头,最后进入的页面放在表尾,当缺页中断发生时,直接淘汰表头的页面,并把新的页面放在表尾。

这种算法有可能置换掉经常访问的页面,导致缺页率升高。

第二次机会页面置换算法

对 FIFO 算法做一个修改:取出表头的页面时,检查该页面的 R 位,如果是 1 表示是最近有访问的,将其清 0,然后放入表尾,然后继续检查下一个表头的页面,直到遇到一个 R 位为 0 的页面,将其换出。

时钟页面置换算法

与上一个算法类似,只不过单链表改成了环形链表,形成一个时钟,移动的也不是页面,而是中间的表针。检查页面逻辑类似,如果该页面 R 为 0,则直接置换该页面,否则将该 R 位清 0,然后表针向前移动。

5. 内存是如何分配的

Linux 分配物理内存的主要机制是页面分配机制(页分配器),使用了著名的伙伴算法,主要用来分配页大小的整数倍的内存(4n KB)。如果是小于页大小的内存分配,通常使用 slab 管理器。通过 slab 分配的内存通常会缓存起来,方便下次使用。

6. 内存是如何回收的?

应用程序用完内存后,可以调用 free() 释放内存,或调用 unmap() 取消内存映射,归还系统。

在内存紧张时,会通过一系列机制来回收内存,如以下三种方式:

  • 回收缓存。主要是页缓存。
  • 回收不常访问的页面。使用页面置换算法,把不常用的页面放到交换区中。
  • 通过 OOM 杀死占用大量内存的进程,释放内存。

虚拟内存可以结合磁盘和物理内存的优势为进程提供看起来速度足够快并且容量足够大的存储
虚拟内存可以为进程提供独立的内存空间并引入多层的页表结构将虚拟内存翻译为物理内存,进程之间可以互相共享物理内存减少开销,也能简化程序的链接、装载以及内存分配过程
虚拟内存可以控制进程对物理内存的访问、隔离不同进程的访问权限,提高系统的安全性