云计算百科
云计算领域专业知识百科平台

LLM 助力的 Linux 内核革新与 1GB 巨页演进

随着大型语言模型(LLM)的爆发式发展,AI 已经深刻影响了软件开发的各个环节。然而,在 Linux 内核 这一高度注重代码质量、极致性能、安全性以及严格同行评审(Code Review)的顶级开源社区中,LLM 的引入过程既充满了探索与创新,也伴随着巨大的争议与谨慎。

本文将系统梳理 LLM 在 Linux 内核开发中的使用现状与前沿案例,深入剖析核心内存管理子系统(MM)中的 hugetlbfs 机制,并完整呈现社区资深开发者如何在 LLM 的协助下尝试攻克“1GB 巨页分配”与“虚拟机内存追踪”两大技术难题。

一、 LLM 在 Linux 内核开发中的使用现状

在 Linux 内核开发中,开发者(尤其是资深内核工程师)通常不会把 LLM 当作“全自动代码生成器”,而是将其定位为高阶辅助工具。

1. 主要使用场景

  • “超级加倍”的橡皮鸭调试法(Rubber Ducking):在动手写代码前,开发者向 LLM 描述内核中的复杂问题(例如内存碎片、锁竞争、虚拟化调度),让 LLM 帮忙推演可能的解法或指出潜在的逻辑盲区。

  • 原型设计与快速迭代:根据设计方案,让 LLM 快速生成补丁(Patch)的大体框架或撰写样板代码(Boilerplate Code),并在收到社区 Review 意见后协助重构。

  • 预审(Pre-review)与文档撰写:在将补丁集发送到 Linux 内核邮件列表(LKML)之前,让 LLM 扮演严苛的审稿人寻找潜在的空指针解引用或内存泄露,同时辅助生成规范的 Commit Message、Git 封面信(Cover Letter)以及内核文档。

💡 内核社区新规范:越来越多由 AI 辅助编写的补丁会在 Commit 中加入 Assisted-by: Claude Opus <…> 或类似标记,以保持透明度。

2. 核心痛点与社区规则

尽管 LLM 能提升效率,但将其直接用于 C 语言编写的高并发内核开发存在严重隐患:

  • 幻觉与“代码犯罪”:LLM 经常凭空发明不存在的内核 API,或写出破坏原子性、引发死锁的代码(如在不可睡眠的上下文中调用可能睡眠的函数)。

  • 缺乏全局上下文:内核代码极其依赖隐式上下文(如 RCU 机制、内存屏障、SMP 对齐),LLM 难以把握几十个文件之间的复杂并发边界。

  • “人类全责”原则:维护者(如 Linus Torvalds)并不关心开发者是否使用了 AI 工具,但提交者必须对补丁的每一行代码承担 100% 的责任。如果代码出了 Bug,不能以“这是 AI 生成的”为由推卸责任。

二、 底层依赖剖析:深入理解 hugetlbfs

在探讨 LLM 如何辅助内存管理开发之前,我们需要先了解 Linux 内存管理中的一个关键机制——hugetlbfs。

1. 背景:为什么要使用“巨页”(Huge Pages)?

在传统的 x86_64 体系架构下,Linux 默认的内存页大小是 4KB。

  • TLB 未命中(TLB Miss)问题:CPU 在访问内存时,需要通过 TLB(页表缓存) 来快速完成虚拟地址到物理地址的转换。如果一个程序(如数据库、高性能虚拟机、DPDK 网络框架)需要使用数百 GB 的内存,使用 4KB 页会导致页表极其庞大,TLB 缓存被快速填满并频繁发生 TLB Miss,CPU 需要花大量时间去查询内存页表,严重影响性能。

  • 巨页的优势:如果改用 2MB 甚至 1GB 的大页,映射同样大小的内存所需的页表项数量会降低成百上千倍。这能大幅提升 TLB 命中率,降低页表开销。

2. hugetlbfs 的工作原理与特点

由于巨页的尺寸远大于默认页,如果像普通内存那样随机分配,系统很容易产生内存碎片导致无法凑出连续的大块物理内存。因此,Linux 引入了 hugetlbfs(Huge Translation Lookaside Buffer File System):

  • 预分配机制:hugetlbfs 依赖系统在开机启动时或运行时提前预留出一块专门用于巨页的内存池。这些内存被单独锁定,不会被普通的内核或用户空间进程占用。

  • 伪文件系统接口:挂载为一个虚拟文件系统(类似于 procfs)。应用程序通过标准的文件操作 API(如 open、mmap)在该目录下创建文件并映射内存,从而获取预留的巨页。

  • 缺乏弹性:传统的 hugetlbfs 相对僵化——如果应用程序申请的巨页数量超过了预先设置的池大小,映射就会失败(引发 SIGBUS 信号),它不会自动降级去使用普通的 4KB 页。

3. hugetlbfs 与透明巨页(THP)对比

维度 hugetlbfs (静态巨页) THP (透明巨页 – Transparent Hugepages)
内存分配 必须提前预分配,独占物理内存 内核根据需要在后台自动将 4KB 页拼成巨页
稳定性与性能 极高。无碎片化干扰,零分配延迟 一般。在内存碎片严重时可能导致分配卡顿
灵活性 低。未使用的巨页无法给其他普通进程使用 高。不使用时可自动拆分为普通 4KB 页
常见应用场景 数据库(PostgreSQL/Oracle)、KVM 虚拟机、DPDK 高性能报文处理 通用桌面/服务器应用程序

三、 社区深度实录:LLM 参与内核核心开发的两种命运

内核社区(与许多其他自由软件项目一样)最近涌现了大量借助大型语言模型(LLM)开发的代码补丁。这些补丁通常来自社区中此前默默无闻的开发者。不过目前,内存管理(MM)领域的开发者们正在评估两套由知名且备受尊敬的资深开发者提交、同样借助了 LLM 辅助的大型补丁集。社区对这两项工作截然不同的接纳态度,或许能让我们窥见未来社区将如何处理由 LLM 生成的贡献。

1. 可靠的 1GB 内存分配

随着 Linux 系统的持续运行,内存往往会趋于碎片化,这使得分配大块且物理连续的内存变得困难重重。多年来,社区为了改善这种状况做了大量工作;内核竭力避免碎片化,并在需要时主动进行去碎片化(整理)。大块内存分配现在比过去可靠得多了。尽管如此,分配上的挑战依然存在,例如,这使得系统在提供 PMD 级别(2MB)的巨型页(huge page)时,很难达到理想的顺畅程度。

鉴于这种难度,可靠地分配 PUD 级别(1GB)的巨型页似乎是个不可能实现的目标。然而,正如 Rik van Riel 在一份包含 40 个补丁的系列文章的封面信(cover letter)中所说,如果某些工作负载能够成功获取 1GB 巨型页,它们将获得显著的性能提升。在当前内核中,唯一能可靠分配这种规模区域的方法是使用 hugetlbfs 子系统,该子系统会在系统引导(启动)阶段为此目的预留内存。但 hugetlbfs 缺乏弹性:其预留的页面不能用于其他用途;如果工作负载需要更多页面,它也无法动态预留。系统管理员只能祈祷在引导阶段设置的预留量能够满足系统随后运行的所有工作负载。

Van Riel 的补丁集尝试在无需 hugetlbfs 预留的情况下,使 1GB 内存分配更加可靠。为了实现这一目标,他采用了多种方法,但核心思想是以称为“超页块(super page blocks)”的单位来管理内存。内核目前将内存拆分为“页块(page blocks)”,并以旨在对抗碎片化的方式来管理它们。其中一项关键技术是将可移动(movable)的分配与不可移动(unmovable)的分配进行隔离。例如,大多数用户空间内存都是可移动的,只需修改所有相关的页表项以作匹配即可。另一方面,内核自身使用的分配通常是不可移动的。通过将这两种类型分开,内核可以把页块内部的页面移动到别处,从而最大化创建出整块空闲页块的机会。

在帮助页分配器(page allocator)提供 PMD 级别的巨型页方面,页块的效果相当不错。但相比于 Van Riel 试图达到的 1GB 目标,页块要小得多;在撰写本文所用的系统上,页块被配置为 4MB 大小。在一个典型的系统中,某些页块会被用于可移动分配,而另一些则用于不可移动分配。在需要时,可移动页块可以被清空,以创建更多 PMD 级别的巨型页。然而,只要存在哪怕一个不可移动的页块,就会导致包含它的整个 1GB 巨型页无法移动,从而造成永久性的碎片化。

引入超页块赋予了页分配器对内存使用情况的更高层级视角。如果收到分配不可移动页面的请求,分配器将像以前一样,尝试从不可移动的页块中进行分配。但是,如果没有包含空闲内存的此类页块,分配器就需要选择一个新的页块来进行分配。Van Riel 的补丁集会让分配器尝试从已经包含其他不可移动分配的超页块中选择该页块。换句话说,可移动与不可移动分配的隔离现在上升到了 1GB 尺度,从而增加了在需要时创建和分配 1GB 巨型页的几率。

为了帮助这一整体策略取得成功,还采用了许多其他技术。例如,考虑一个需要多个页面的虚拟映射内核空间分配(如通过 kvmalloc() 获取的分配)。这种分配是不可移动的,因此应该放入不可移动的超页块中。如果没有具备足够连续页面的此类超页块,分配器自然会选择一个新的超页块,从而“污染”它并使其变为不可移动。但是,如果通过将该分配拆分为更小的块,就能从现有的不可移动超页块中满足要求,那么分配器就会采取拆分的方式。

该系列补丁包含一个 Assisted-by 标记,表明在创建过程中使用了 Claude Opus LLM。不过如前所述,van Riel 并不是那种需要借助 LLM 才能拼凑出内核补丁的新手开发者。他在 LWN 上的首次被提及可以追溯到 1998 年关于内存碎片化的讨论;当时他提出了引入分区内存分配器(zoned memory allocator)的设想,该设想随后变为了现实。在选择工具方面,他属于那种很容易获得社区信任(give the benefit of the doubt)的开发者。

然而,尽管其目标——可靠地分配 1GB 巨型页——获得了广泛支持,但这套特定的补丁集并没有受到一致的好评。最犀利的批评无疑来自 Lorenzo Stoakes 的这封长邮件,他对该系列补丁的组织结构和其中的代码提出了异议:“就目前而言,这套补丁完全不可能合并。差得太远了。”补丁集的其他部分被描述为“对 __rmqueue_smallest() 施加的代码战争罪行”,或者是“你在 90 年代 PHP 网站上才会看到的东西,而不是在核心 MM 代码里”。他在结尾写道:

好了,说了这么多——为了表达得绝对清楚——我非常尊重你,而且我知道你比这(写出的水平)要优秀得多(得多)。

再次重复,这个想法令人兴奋,我希望看到它落地。

但我觉得你有点让 LLM 撒欢乱跑了,它(生成的劣质代码)实在太对不起你的才华了,毕竟你是如此聪明和有能力。

Van Riel 回复说,他从未指望代码能以当前的形态被合并,他其实一直希望能先获得对整体设计的反馈,然后再将其重构为可以考虑合并的形式。然而,抛出的大量 LLM 生成的代码阻碍了这一过程。开发者们希望通过查看设计的具体实现来理解它在实践中是如何工作的,而在这个案例中,这被证明是极其困难的。这项工作必须重新来过,投入更多的人力关注,然后才能在设计层面上被严肃对待。

2. 虚拟机 Guest 内存的活跃集(Working-Set)追踪

虚拟机(VM)受制于两个层面的内存管理。它们在内部处理自己的内存,但同时也存在宿主机(Host)层面的管理,试图确保系统的物理内存被所有运行的 VM 高效使用。如果虚拟机管理器(Hypervisor)能够直观了解给定 VM 实际上正在使用哪些页面,宿主机层面的任务就会轻松得多;该信息可用于回收较冷(不常用)的页面(或将其移动到较慢的内存中)。但这些信息往往被封闭在 VM 内部。

Kiryl Shutsemau 的这套补丁旨在让 VM 管理器更容易获取这些使用信息。它为 userfaultfd() 系统调用添加了一种新的注册模式,该模式会导致指定页面范围在宿主机层面的保护被标记为“无权限访问(no access)”。在注册时,可以选择当虚拟机确实访问这些页面之一时发生情况的两种替代方案。如果选择了同步模式,VM 管理器将收到来自内核的消息,并在记录下该缺页中断后,通过向内核发出的另一个请求来解决它。在异步模式下,内核会在不通知 VM 管理器的情况下重置权限。稍后,管理器可以扫描该页面范围,以查看哪些页面已被访问。

这些补丁同样包含标明 Claude Opus 的 Assisted-by 标记。Shutsemau 在内核社区资历没有 Van Riel 那么深;他在 2008 年的 2.6.25 内核中做出了他的首次贡献,算是一个相对的“新人”。尽管如此,他的履历足够丰富,足以表明他完全有能力理解自己提交给社区的工作。

这套补丁已经经历了七次修订,并根据收到的评审做出了重大修改。与 Van Riel 的工作受到的待遇不同,在这些评审中,没有任何人对 LLM 在创建这项工作中扮演的角色提出担忧。不过,在回应第二版修订时,Andrew Morton 确实询问了关于 LLM 是如何被使用的信息;Shutsemau 作出了详细的答复。该工具很大一部分作用在于验证想法:

对于这个特定的项目,有相当多的探索探路工作。我经历了一个与 Claude 交流碰撞想法的阶段。它帮助我更好地理解问题空间并构想可能的解决方案。就像是“超级加倍版”的橡皮鸭调试法(Rubber ducking)。

一旦明确了做什么,我们就制定一个关于怎么做的计划。这也涉及反复的沟通。

计划制定完成后,我给出了执行的指令。

他说,这个过程中最耗时的是审查生成的代码;这涉及止步并从头开始重来不止一次。他花了“大约 8 到 10”轮沟通才得到了自己满意的代码——在此之后,才将整个补丁集连同另一套提示词喂给 LLM 进行审查。

这种工作流程似乎产生了一套可行的、对核心内存管理代码做出重大修改的补丁集。相较于前面提到的那项工作,其成功的关键似乎在于投入了大量的人力时间去促使工具正确地完成工作,并在此后妥善解决遗留的问题。在补丁投递到邮件列表之前,为了确保它们达到社区期望的质量水平所付出的心血,似乎起到了决定性的作用。

Shutsemau 没有透露这整个过程是否比不借助 LLM 辅助直接动手效率更高,但他似乎倾向于在未来再次使用这种流程。

Shutsemau 邮件的结尾是邀请其他开发者分享他们使用 LLM 工作的流程,但没有收到任何回应。说实话,当谈到针对核心内核的重大工作时,他似乎是先驱者之一。然而,他所描述的这条走向成功的道路看起来并不平坦;任何希望利用 LLM 作为快速成为内核开发者捷径的人,都应该好好留意这个很可能成为迄今为止(针对内核代码)最大成功案例的经验。

四、 结语

从克服 hugetlbfs 静态限制的“1GB 超页块”探索,到改进虚拟化内存回收的 userfaultfd 补丁,Linux 内核开发正在经历深刻的范式演变。

这两个真实的社区案例表明:LLM 在内核领域的定位将长期停留在 “超级橡皮鸭” 和 “初级打字员” 的角色。任何试图依靠 AI 快速甩出大量代码而缺乏精细审查的做法,都会遭到内核社区的严厉拒绝;而唯有将人类专家的架构经验、严谨的逻辑把关与 AI 的高效迭代深度融合,才是利用 LLM 推动内核底层创新的正确道路。

赞(0)
未经允许不得转载:网硕互联帮助中心 » LLM 助力的 Linux 内核革新与 1GB 巨页演进
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!