LWN:优化内存中经常需要访问的匿名页!

关注了就能看到更多这么棒的文章哦~

Working-set protection for anonymous pages

By Jonathan Corbet
March 19, 2020

原文来自:https://lwn.net/Articles/815342/

内核中的memory-management subsystem竭尽全力在确保那些正在使用的page要在内存之中。不过有时候确实没法做到,从而导致性能下降,或者最坏情况下还会导致内存大量换入换出。得益于Joonsoo Kim的patch set,我们很可能很快就能看到在这个方面的巨大改善了。这个patch set改变了匿名页(anonymous page,指那些不是从磁盘上的文件而来的数据页面,也就是不属于file-backed页面)的管理方式。现在看来,唯一需要去做的就是如何利用现在memory-management代码中其他地方早已用起来的一个机制就好。

LRU lists

首先介绍一些背景信息会有助于理解这个patch set的工作机理。我们先来尽量简化一下,然后再慢慢增加细节。

虚拟内存系统,允许应用程序可以寻址使用远超过本机真实物理内存大小的空间,也就是说,在任一时刻中,某个进程的地址空间中很大一部分内容都是存放在二级存储上(译者注:例如swap分区)的。显然,进程接下来要用的内存页面最好都在物理内存之中。而kernel其实无法完全清楚哪些内存是真正要用的,只能基于一些假设来尽量预测一下。

有些假设条件的合理性可以很容易的就理解。比如,如果发现某个进程一直在对一个文件进行顺序访问,那么大概率来说它接下来会访问文件中当前正在访问的位置之后紧接着的数据。此外,绝大多数虚拟内存管理实现方案中都基于的一个共同假设,就是最近使用过的页面接下来很可能还会用到,而那些已经有段时间未用到的页面则通常不值得继续保留了。

为了实现后者这个机制,kernel里面维护了一个“least-recently used”(LRU,最近最少使用)list。物理内存中的属于user-space的页面都由这个链表来串起来。kernel时不时会查看一下LRU list上的页面,把那些最近访问过的页面移到list头部。当需要更多内存的时候,为了从二级存储设备上移入一些页面,会首先回收LRU list末尾对应的这些内存页面。

实际上kernel维护了不止一个LRU list。首先,“LRU list"实际上就包含了两个list:“active”和“inactive” list。其中的active list的功能基本就是上面一段中介绍的那样,只不过当要移除list末尾的页面的时候,其实是把它串到inactive list上去。在这个时刻,这些页面的访问权限就会被修改为不允许user-space access。如果有某个进程访问了其中一个内存页面的话,就会发生一次“soft” page fault(比较“温和”的内存缺页中断),从而马上开放对这个page的访问权限并把它加回active list上。在需要内存的时候,就会从inactive list回收内存页面。

因此inactive list就像是给这些page的第二次机会一样。不过它还有另一个职责:用来管理那些大概率会只用到一次的页面。有个经典的例子就是在进程读取某个文件的时候,读入内存的内容很可能只需要处理一次之后就不再需要了。这些内存页面不应该把其他那些近期还会用到的页面从物理内存中挤出去。kernel会把这些newly faulted, file-backed page(来自文件的数据、新近加载入物理内存的页面)直接放入inactive list,如果在被回收之前又访问过,才会把它们加入active list。

实际上情况更加复杂。根本不止2个LRU list。感兴趣的读者一定知道,针对file-backed(来自文件的页面)和anonymous page(匿名页)这两种情况,都有单独的active和inactive list。回收内存时,通常优先回收file-backed页面,然后才是匿名页,因为前者通常不需要写回,而匿名页则必须每次都写回到swap里面去,并且在下次需要的时候,读入文件内容也更加容易。需要注意针对这些file-backed内存页面,kernel还会维护一些“shadow entries”来记录近期从inactive list里面回收掉的那些page。如果这些page再次通过page fault机制回来,kernel就知道它之前把一些有用的页面错误地回收了,因此会做一些调整来避免下次出现。这个机制被称之为refault tracking。

Improving anonymous LRU-list behavior

Kim的patch set主要是针对匿名页和file-backed页面的处理方式中的两个主要区别。首先,file-backed页面会经过缺页中断加入inactive list,流程如上面所述,但是匿名页则直接进入active list。假如某个应用程序通过page fault加载了许多匿名页进来,那么就可能会把其他一些仍然有用的页面从active list挤到inactive list去。尽管这些新进来的页面可能只需要用一次,它们还是会把其他一些更加需要重复使用的页面不必要地挤出去。为了解决这个问题,Kim的patch set会也让匿名页先加入inactive list,跟file-backed页面处理机制一致。如若这些页面真的很有用,那么就会在soft fault发生的时候提升到active list去;否则的话就可以更快的被回收掉。

另一个改动是关于refault tracking的。目前的内核中,refault tracking只会对file-backed LRU list进行。当匿名页被回收的时候,内核会完全忘掉这些历史信息。我们观察到,上一个改动(缺页处理时直接把页面加入inactive list)可能会极大恶化这种情况:在inactive list加入新的页面会导致此前刚刚进来的页面在被第二次访问(从而可以加到active list)之前就被快速挤掉了。因此如果对匿名页的LRU list也增加refault tracking机制,就能检测到这种问题从而得到处理。

因此这个patch set就对匿名页也加上了refault tracking。做法其实很简单直接,毕竟refault tracking所依赖的代码早就已经存在,可以直接拿来用,仅仅需要扩展一下,不局限于只支持一个LRU list即可。不过这里还有一些其他细节要考虑。举个例子,因为匿名页在被回收的时候需要把内容写入swap,那么用来跟踪refault事件的shadow LRU entry也可以在这个时候写swap,并不需要一直留在RAM。

Kim也提供了一些跑分数据可以看到在各种情况下对memory-management功能行为的改善。不过memory-management maintainer Andrew Morton最关注的则是有一个自动测试结果表明在virtual-memory scalability test中有400%的提升。他问道:“One wonders why on earth we weren't doing these things in the first place?” Kim的回复中附上了2002年增加这个机制的patch,正是由Andrew Morton提出的patch。Morton很不好意思地说看来是要重新看一下当时的做法对于现在的kernel是否依然适用了 :)

目前在memory-management community里面看起来没有任何反对意见。这并不意味着就能很快合入了,memory-management patch通常需要经过无数测试以及review,然后开发者们才有信心合入。尤其是对于那些会影响一些启发式条件的patch格外需要注意,因为通常都会在意想不到的地方导致一些意外结果。这些patch甚至还没有合入-mm tree,只有走到这一步了之后才会得到更多的测试和review。因此,哪怕Morton说了“given all the potential benefits, perhaps I should be more aggressive here”,不过估计还是进不去Linux 5.7。不久之后应该会能进入mainline的。

全文完

LWN文章遵循CC BY-SA 4.0许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注LWN深度文章以及开源社区的各种新近言论~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值