LWN:尽快释放被杀死的进程内存
Expedited memory reclaim from killed processes
By Jonathan Corbet, April 12, 2019
https://lwn.net/Articles/785709/
Linux运行时如果内存不足了会很难处理,最坏情况下没有其他方法能缓解,只得开始kill进程来回收内存。kill进程的动作可能是kernel自己来进行,也可能是由用户系统(例如Android)通过在user-space实现一个out-of-memory(OOM)的监控进程来kill。可以肯定的是被kill的进程肯定不爽,那么kernel应该尽量快地回收这个进程的内存空间,试图避免继续kill别的进程。可是目前kernel里面行为,有时候并不是这样的。
Suren Baghdasaryan提交的一组patch就是希望能改善这个现象。不过目前这组patch争议颇多,最终解决方案可能会完全是另一个样子。Kernel里面要求每个进程在exit的时候清理他们自己的资源。因此在某个进程被OOM killer杀死后,它需要先在kernel里面得到运行的机会来释放它所占用的memory resource给内存管理系统。如果这个进程的优先级太低,或者它一直在等待系统里的其他什么资源,那么就会花费很长时间才能完成清理工作。与此同时,系统因为没有得到原本应该释放出来的memory,所以仍然资源非常紧张,很快就会去kill第二个进程来继续释放它的内存。
2015年就有OOM reaper方案被提出来,希望解决这个问题。当kernel的OOM killer准备kill一个进程的时候,它会尽快把这个进程的内存剥夺掉,不允许它再访问。不过OOM reaper方案无法让user-space的OOM killer进程来调用。那些user-space的OOM killer只能发送SIGKILL signal来通知目标进程尽快退出,然后就听天由命了,它才搞不清楚被kill的进程会花费多长时间才能真正退出以及释放资源。Baghdasaryan指出,这里带来的负面影响就是user space必须要预留一个比较大的free pages,并且要提前开始kill进程。
Baghdasaryan的方案是为Linux 5.1里面引入的pidfd_send_signal()增加了一个flag:SS_EXPEDITE。调用时如果提供了这个flag,就说明调用者有CAP_SYS_NICE的能力并且发送的signal就是SIGKILL,然后OOM reaper就可以尽快剥夺被kill进程的资源。如此一来user space的OOM killer也能尽快kill某个进程及释放资源了,不用担心会不会目标进程被什么其他事情给拖慢了。
有趣的是虽然大多数人都赞同这个目标,但是review comments整体却都是各种异议。最主要的反对意见来自Michal Hocko(OOM reaper的作者),他抱怨说:“这个方案是滥用了OOM的的一个行为,把它变成了一个正式的API”。他还在问,这个能力是否真的有用,因为依赖清理的速度是“一个基本的设计问题”。Johannes Weiner却针对这个观点提出不同看法:“就要让用户体验优化到最好”。其他人基本都同意在进程退出的时候应该快速释放内存。
Daniel Colascione挺喜欢这个注意,不过想要改一下这个接口(interface),他觉得不应该绑定到某个signal,而是增加一个新的system call(系统调用),类似这样:
size_t try_reap_dying_process(int pidfd, int flags, size_t max_bytes);
调用这个系统调用就会剥夺pidfd所指向的进程的内存(这个动作只在进程退出的时候才发生)。max_bytes这个参数用来告诉kernel,发起系统调用的人(user-space OOM killer)希望能拿到多少内存。这样kernel就不用把被kill进程的所有内存都剥夺掉了,只需要达到max_bytes数量即可。需要注意的是,剥夺内存的动作是发生在发起系统调用的进程空间里,这样user space就能根据当前进程的重要性来决定kill和释放的内存数量细节。
Matthew Wilcox提出一个简单的问题:为什么不在进程退出的时候直接尽快回收内存,而要等这个特殊的系统调用才做这件事?Weiner同意他的观点,既然释放内存总是要做的,干脆每次都马上处理掉即可,不用那么麻烦再去调用一个系统调用。不过Daniel Colascione指出这个机制会减慢SIGKILL的处理流程,例如killall执行的时候就可能观察到变慢了。
Baghdasaryan也不觉得“每次”剥夺内存都尽快完成是一个合理的需求。不过,确实在有些时候这个是非常必要的:“如果我们能不依赖user space的参数和提示就了解到哪次操作是紧急的,哪次操作不是,那就太好了。所以我很欢迎大家提出一些方案能不依赖一个新的flag”。如果能找到这样的一个方案,最终估计会得到大家的赞同从而合并入Linux kernel。无论如何,清理一个被kill的进程的工作,都是kernel的责任。大家不太会喜欢创建一个新的interface来把这个责任转移给user space,最好还是能找到一个不依赖新的API的方案,让我们拭目以待吧。
全文完
极度欢迎将文章分享到朋友圈热烈欢迎随意转载,只需保留出处~
长按下面二维码关注:Linux News搬运工,希望每周的深度文章以及开源社区的各种新近言论,能够让大家满意~