专题:Linux内存管理专题
关键词:OOM、swap、HMM、LRU。
本系列没有提到的内容由THP(Transparent Huge Page)、memory cgroup、slub、CMA、zram、swap、zswap、memory hotplug等。
下面列举从Linux 4.0到Linux 4.10中在内存管理方面的更新内容。
1. 页面回收策略从zone迁移到node
页面回收策略从基于zone迁移到基于node策略的一个主要原因是在同一个node中不同zone存在着不同的页面老化速度(page age speed)。
这样会导致很多问题,例如一个应用程序在不同的zone中分配了内存,在高端zone(ZONE_HIGH)分配的页面有可能已经被回收了,而在低端zone(ZONE_NORMAL)分配的页面还在LRU链表中,理想情况下他们应该在同一个时间周期内被回收。
从另外一个角度来看zone的各个LRU链表的扫描覆盖率应该趋于一致,也就是给定的时间内,一个LRU链表被充分扫描了,另外的LRU链表也应该如此。即不同zone的LRU扫描充分程度不一样。
究其原因在于页面回收内核线程kswapd和页面分配内核代码路径page allocator之间复杂的扫描逻辑。
基于node的页面回收机制可以有效解决这个问题。
2. OOM Killer改进
OOM Killer的改进主要有OOM检测和OOM reaper。
系统分配内存失败时会调用直接回收机制(direct reclaim) 来回收一些内存。
有些情况下直接回收机制返回成功,但有些情况下回收页面需要等待脏的内容写回磁盘,此时这些脏页面是不可用,虽然他们最终会变成空闲页面,但时间不确定。
因此目前的内核会勉强调用OOM Killer。
在Linux 4.7,Michal Hocko提出了新的OOM检测机制:系统分配内存失败时,特别是如果到最后调用直接回收机制(__alloc_pages_direct_reclaim())还是失败,它会去不断尝试并检测当前的空闲页面和可回收页面是否满足分配的需求,最多会尝试16次,只有这些尝试都失败才会去调用OOM Killder。
OOM reaper的机制:当一个进程收到SIGKILL信号时,代表它不会在用户态继续运行,可以在进程被销毁之前收割其拥有的匿名页面。
OOM reaper的实现比较简单,它会创建一个名为“oom reaper”的内核线程来做内存收割。
3. swap优化
当系统内存紧张时,swap子系统把匿名页面写入swap分区从而释放出空闲页面,长期以来swapping动作是一个低效的代名词。
提高页面回收的效率,主要集中在如下两个方面。
- 优化LRU算法和页面回收机制。
- 优化swap性能。
第一个方面的优化包括:过滤只读一次的page cache风暴、调整活跃LRU和不活跃LRU的比例、调整匿名页面和page cache之间的比例、Refault Distance算法、把LRU从zone迁移到node节点等。
第二个方面就是优化swap性能。
回收匿名页面要比回收page cache要复杂得多,一是如果page cache的内容没有被修改过,不需要写回到磁盘文件中,直接丢弃即可;二是通常page cache都是从磁盘读取或者写入大块连续空间,而匿名页面常是分散地写入磁盘交换分区中,scattered IO操作很浪费时间。
4. 展望
HMM(Heterogeneous Memory Management)提供一个统一和简单的API来映射进程地址空间到外设的MMU上,这样进程地址空间的改变就可以反映到外设的页表中。
建立一个共享的地址空间,系统内存可以透明地迁移到外设内存中。HMM新定义一个名为ZONE_DEVICE的zone类型,外设内存被标记为ZONE_DEVICE,系统内存可以迁移到这个zone中。
从CPU角度看,就想把系统内存swapping到ZONE_DEVICE中,当CPU需要访问这些内存时会触发一个缺页中断,然后再把这些内存从外设中迁移回到系统内存。