Linux 2.6 中的页面回收与反向映射
简介: 本文主要介绍 Linux 2.6 中的页面回收机制是如何工作的,反向映射是如何设计并实现的,以及 Linux 操作系统如何利用反向映射机制进行页面地回收。 Linux 2.6 中关于反向映射和页面回收的代码在不断地更新,不同版本的内核在这部分的代码上会有很大差异,本文将基于 2.6.18.1 版本的内核来探讨 Linux 中的反向映射和页面回收。
为什么要进行页面回收
操作系统管理内存中的物理页面,同时也担任着内存分配的职责。应用程序可以通过内存分配函数向操作系统申请物理页面;在使用完这些物理页面之后,应用程序可以通过相应的内存释放函数释放这些物理页面。但是,对于内存中的某些物理页面来说,页面的使用者并不会主动释放它们,如果这些物理页面一直被占用而得不到释放,那么无论计算机上可用的物理内存有多少,物理内存迟早都有被用完的时候。所以,对于无法被主动释放的物理页面来说,操作系统就需要提供相应的功能去释放它们,Linux 中提供页面回收算法这样一种机制进行页面回收。
一般来说,用于页缓存的物理页面无法被页面的使用者主动释放,因为它们不知道这些页面何时应该被释放。Linux 中页缓存存在的最大好处就是可以让程序从缓存中快速获取数据,从而提升系统的性能。在系统负载不重的情况下,Linux 操作系统会分配较多的物理页面用于页缓存,从而提高程序的运行效率;但是在系统负载较重的情况下,Linux 操作系统就可能会适当回收用于缓存的页面,并减少用于缓存的页面的分配,从而满足系统中优先级更高的内存分配请求。对于用户进程来说,Linux 操作系统可以在它需要的时候为它分配物理内存,但是当用户进程不再需要这些物理页面的时候,如果用户进程不主动释放占用的页面,Linux 操作系统也不会强制用户进程去释放这些物理页面。基于上述这些情况,当内存中可用的物理页面越来越少,并最终导致内存的使用捉襟见肘的时候,为了保证系统的顺利运行,Linux 操作系统就会根据一定的算法去回收那些长期被占用并且没有得到有效使用的物理页面。
由操作系统内核本身使用的物理页面不在 Linux 操作系统进行页面回收的考虑范围之内,这是因为与用户进程相比,内核不需要占用非常多的内存,回收内核占用的物理页面会显著增加内核代码的复杂性,潜在收益非常低。
如何进行页面回收
哪些页面可以被回收
内存中并非所有物理页面都是可以进行回收的,总的来说,以下这些种物理页面可以被 Linux 操作系统回收:
- 文件读写操作过程中用于缓冲数据的页面
- 用户地址空间中用于文件内存映射的页面
- 匿名页面:进程用户模式下的堆栈或者是使用 mmap 匿名映射的内存区
- 特殊的用于 slab 分配器的缓存,比如用于缓存文件目录结构 dentry 的 cache,以及用于缓存索引节点 inode 的 cache
在页面被操作系统回收之前,所有与之关联的进程页表项必须要断开与该页面之间的映射关系。对于匿名页面来说,在页面被回收之前,匿名页面中的内容首先需要先被交换到交换区中去;如果要回收的页面是“脏”页面,那么该页面在被回收之前需要先将页面中的数据写回。
除此之外,其他的页面要么不可以被回收,要么根本不必进行回收。比如,内核占用的页面不会被回收;映射到内核空间中的页面也不会被回收;内核在执行的过程中动态生成的页面需要永驻内存;被锁住的页面不能被回收;而没有被占用的物理页面则根本不需要被回收。
进行页面回收的时机
Linux 操作系统使用如下这两种机制检查系统内存的使用情况,从而确定可用的内存是否太少从而需要进行页面回收。
- 周期性的检查:这是由后台运行的守护进程 kswapd 完成的。该进程定期检查当前系统的内存使用情况,当发现系统内空闲的物理页面数目少于特定的阈值时,该进程就会发起页面回收的操作。
- “内存严重不足”事件的触发:在某些情况下,比如,操作系统忽然需要通过伙伴系统为用户进程分配一大块内存,或者需要创建一个很大的缓冲区,而当时系统中的内存没有办法提供足够多的物理内存以满足这种内存请求,这时候,操作系统就必须尽快进行页面回收操作,以便释放出一些内存空间从而满足上述的内存请求。这种页面回收方式也被称作“直接页面回收”。
如果操作系统在进行了内存回收操作之后仍然无法回收到足够多的页面以满足上述内存要求,那么操作系统只有最后一个选择,那就是使用 OOM( out of memory )killer,它从系统中挑选一个最合适的进程杀死它,并释放该进程所占用的所有页面。
上面介绍的内存回收机制主要依赖于三个字段:pages_min,pages_low 以及 pages_high。每个内存区域( zone )都在其区域描述符中定义了这样三个字段,这三个字段的具体含义如下表 1 所示。
表 1. 字段含义
名称 | 字段描述 |
---|---|
pages_min | 区域的预留页面数目,如果空闲物理页面的数目低于 pages_min,那么系统的压力会比较大,此时,内存区域中急需空闲的物理页面,页面回收的需求非常紧迫。 |
pages_low | 控制进行页面回收的最小阈值,如果空闲物理页面的数目低于 pages_low,那么操作系统内核会开始进行页面回收。 |
pages_high | 控制进行页面回收的最大阈值,如果空闲物理页面的数目多于 pages_high,则内存区域的状态是理想的。 |