2004年9月28日,一则只有几百字的邮件回复出现在Linux内核邮件列表上。它没有贴出补丁,也没有讨论代码实现,而是讲了一个关于飞机、燃油和乘客的故事。但这则故事,却成了此后二十年里,人们理解Linux内存回收机制最锋利的隐喻。
故事的前一天,开发者Thomas Habets提交了一个名为“oom_pardon”的补丁,并留下了一句火药味十足的提议:能不能加一个sysctl,让内核“看在上帝的份上,永远别在内存耗尽时杀掉这些进程。如果别的都不能杀,我宁愿你直接panic”?(原文:How about a sysctl that does "for the love of kbaek, don't ever kill these processes when OOM. If nothing else can be killed, I'd rather you panic"?)这条请求毫不含糊地表达了对Linux OOM Killer默认行为的不信任——不是反对杀掉进程,而是要求在特定情况下,宁可系统崩溃,也别动我指定好的那几个。
![]()
这个诉求本身,就是一场辩论的导火索。正方逻辑很直白:有些进程是用户的底线,比如正在跑的科学计算、尚未保存的文档会话,甚至是桌面上的锁屏程序xlock。一旦被OOM Killer误判为可牺牲对象,损失远大于一次死机。于是Thomas试图用一条硬性豁免规则,在内存熔断机制上划出一块“不杀特区”。这一主张背后的情绪,是许多用户面对OOM时的共同体验:你明明有八个G的交换空间,刚刚只是打开了一个大文件,为什么非要把我刚写了三个小时的笔记进程杀掉?
但内核维护者并没有直接回答这个技术问题,而是用一个寓言,将整个OOM机制的设计逻辑撕开了一个口子。这个由LWN.net编辑corbet投下的故事,就是那封回复的主体,也是Linux圈子里流传至今的“飞机抛客”比喻。故事讲的是一家飞机制造公司发现,少装燃油能让飞机变轻、省钱省油。极少数情况下,飞机真会遇到燃油耗尽,一头栽下去。工程师们的解决方案,并不是多加油,而是开发了一套名为OOF(Out-Of-Fuel)的应急机制:在紧急时刻,选出一名乘客扔出机舱,必要时可以重复扔。很快,理论体系建立起来了,无数论文讨论如何“正确挑选受害者”:随机选?扔最重的人?扔最老的?乘客该不该花钱买豁免,从而让最穷的人成为牺牲品?如果扔的是最重的人,发现被扔的是飞行员怎么办?头等舱旅客能不能免于被扔?
这个比Windows蓝屏更荒诞的剧情,精确对应了OOM Killer的每一个设计点。飞机少装油,对应的是系统总倾向于超额分配内存,赌大多数进程不会同时用尽自己的份额。燃油耗尽坠机,就是物理内存耗尽、系统再无缓冲的状态。OOF机制,则直接指向Linux引入OOM Killer的初衷:与其让整个系统僵死,不如牺牲一个进程换取全局存活。而挑选受害者时需要考虑的体重、年龄、付费能力、社会身份,正好对应OOM Killer在计算badness分数时参考的进程内存占用、运行时长、oom_score_adj、是否为root进程、是否持有重要锁等维度。飞行员豁免对应了内核线程不可杀,头等舱特权对应了管理员手动调高oom_score_adj保护关键服务。这一整套比喻,用一种黑色幽默的方式,把内核内存回收策略中隐藏的粗暴与无奈,全都抖了出来。
但最狠的一刀留在结尾:自从有了OOF机制,即使没有燃油短缺,这个扔人程序也时不时会自行启动,把乘客丢出舱外。工程师们至今还在研究,这故障究竟是怎么引发的。这句话放在OOM语境下,就是在描述一个令无数运维人员血压升高的现实——OOM Killer经常在系统仍有大量Swap缓存、处理负载尚未饱和时被错误激活。它挥刀的速度,往往比应用释放内存的速度更快。这正是Thomas提出“宁可panic也不准杀”的动机之一:如果连豁免机制都没有,那么每一次OOM动作都可能是一次误杀,而用户只能看着日志里的out_of_memory字串,连解释权都在内核那边。
正反方观点交锋到此处,其实已经不需要胜负宣判。Thomas的方案是要硬性豁免,属于在现有机制上打补丁式的保守疗法;corbet的寓言则直接指向病因——只要内核延续“先超售、再牺牲”的内存管理传统,那么任何挑选算法都会留下冤魂。寓言中的航空工程师没有去多加油,内核社区也没有彻底走向基于cgroup的内存保障与精确记账,而是持续在OOM策略里修修补补。于是二十年来,oom_score的计算逻辑调整了无数次,oOM_kill_allocating_task由默认关闭到可选开启,内存压力失速控制也逐步成熟,但那个根本的困境依然在:我们仍然在用牺牲进程的方式,为内存超售政策兜底。
我的判断很明确。这则2004年的寓言从未过时,因为它并不只是在批评OOM Killer这个机制,而是在揭示任何一种资源回收系统若缺乏主动保障,就会走向盲目牺牲的必然路径。无论硬盘的配额回收、容器的驱逐策略,还是云原生环境下的Pod Eviction,底层逻辑都和飞机抛客如出一辙。解决之道不是找到一种完美的挑选算法,而是像现代航空业那样,把油箱装满,不许为了省油而拿乘客的命去赌。翻译成技术语言,就是让内存分配从一开始就走向硬性担保,而不是依赖事后挥刀。只不过这场手术要动的地方太多,直到今天,各个操作系统仍然迈不出那一步。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.