
内存回收是把已经使用过的的物理页帧重新放回到内核中的buddy系统(buddy系统用于申请空闲物理页帧的子系统)管理中,解决内存紧张的问题;内存回收的页帧包括未修改的文件页帧、修改且完成同步的文件页帧、换出到设备的匿名页帧。回收过程就是接触这些页帧的使用,归还给buddy子系统。
RAW内存总量不做严格的约束,当系统负载相对较低的时候,内存大部分被磁盘高速缓存使用,随着系统负载增大,系统进程使用的内存越来越多,磁盘的高速缓存占用的内存就会被缩小,内存页帧的回收必须在消耗所有空闲页帧之前进行,这个是为了安全。如果内核尝试回收后仍然无法获得物理页帧,内核会执行find_bad_process找到一个进程并且执行OOM Kill释放这个进程占用的物理页帧。
slab allocation,它用于内核数据结构的申请。slab分配器在频繁申请和释放的情况下效率比较高LRU页帧链表zone将空闲页帧和已经在使用的页帧分别用buddy系统和
zone的LRU链表管理。struct zone {
// 用于空闲页帧管理的buddy系统
struct free_area free_area[MAX_ORDER];
// 已经在使用的LRU链表管理
struct pglist_data *zone_pgdat;
atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
}
// 用于管理已经在使用的内存页帧
typedef struct pglist_data {
spinlock_t lru_lock;
// LRU 链表
struct lruvec lruvec;
atomic_long_t vm_stat[NR_VM_NODE_STAT_ITEMS];
} pg_data_t;LRU链表类型种类定义在enum lru_list(最大是NR_LRU_LISTS).内核将文件页帧和匿名页帧各自分别形成2个LRU链表。active和inactive的文件页帧和匿名页帧的LRU链表,最后内核除了这4个LRU还会有第5个不可换出页的LRU。pglist_data有NR_LRU_LISTS个,每个pglist_data包含一个LRU链表。// LRU链表
struct lruvec {
struct list_head lists[NR_LRU_LISTS];
struct zone_reclaim_stat reclaim_stat;
/* Evictions & activations on the inactive file list */
atomic_long_t inactive_age;
/* Refaults at the time of last reclaim cycle */
unsigned long refaults;
#ifdef CONFIG_MEMCG
struct pglist_data *pgdat;
#endif
};
enum lru_list {
// 不活跃的匿名页帧
LRU_INACTIVE_ANON = LRU_BASE,
// 活跃的匿名页帧
LRU_ACTIVE_ANON = LRU_BASE + LRU_ACTIVE,
// 不活跃的文件页帧
LRU_INACTIVE_FILE = LRU_BASE + LRU_FILE,
// 活跃的文件页帧
LRU_ACTIVE_FILE = LRU_BASE + LRU_FILE + LRU_ACTIVE,
// 不可换出的页帧
LRU_UNEVICTABLE,
NR_LRU_LISTS
};
LRU链表中未使用的

直接回收和定期回收。直接回收是发生在分配页帧时候发现空闲页帧不足的情况下。直接回收和定期回收底层都是走相同的逻辑,但是直接回收是实在紧急情况下进行,必须做到回收到足够的页帧。定期回收则是内核的守护进程定期发起,尽量回收,保留足够的空闲空间。