您现在的位置是:首页 > 文章详情

jemalloc 作者自述:开发已陷入停滞

日期:2025-07-23点击:63

jemalloc内存分配器最初于2004年初构思,并且现在已公开使用了大约20年。由于开源软件许可的性质,jemalloc将无限期地保持公开可用。但积极的上游开发已结束。本文简要描述了jemalloc的发展阶段,每个阶段都有成功/失败的亮点,随后是一些回顾性的评论。

阶段0:Lyken

2004年,我在科学计算的背景下开始开发Lyken编程语言。Lyken最终成为了死胡同,但其手动内存分配器在2005年5月已经功能完整。(本应利用其功能的垃圾收集器从未完成。)2005年9月,我开始将分配器集成到FreeBSD中,并在2006年3月,为了使用线程特定数据和dlsym(3)实现的薄封装,我从Lyken中移除了分配器。

在投入了这么多精力之后,为什么又要从Lyken中移除内存分配器呢?一旦将分配器集成到FreeBSD后,就明显发现系统分配器的唯一缺失功能是跟踪分配量的机制,以便触发线程垃圾收集。而这可以通过使用线程特定数据和dlsym(3)的薄封装来实现。有趣的是,多年后,jemalloc甚至添加了Lyken需要的统计收集功能。

阶段1:FreeBSD

2005年,多处理器计算机的转变正在进行中。FreeBSD拥有Poul-Henning Kamp的出色phkmalloc内存分配器,但该分配器没有并行线程执行的机制。Lyken的分配器似乎是一个明显的可扩展性改进,经过朋友和同事的鼓励,我将它快速集成到了众所周知的jemalloc中。但等等!在集成后不久,就发现jemalloc在某些负载下有严重的碎片问题,尤其是由KDE应用程序引起的。正当我以为已经差不多完成时,这个现实世界的失败质疑了jemalloc的可行性。

简而言之,碎片问题是由于使用了统一的范围分配方法(即没有大小类区分)。我从Doug Lea的dlmalloc获得了一些基本灵感,但没有那些复杂的、经过实战测试的启发式方法来避免许多最严重的碎片问题。随后进行了大量的研究和实验。当jemalloc成为FreeBSD发布的一部分时,其布局算法完全改变了,采用了大小分组的区域,如2006年BSDCan的jemalloc论文所述。

阶段1.5:Firefox

2007年11月,Mozilla Firefox 3即将发布,高碎片化问题仍未解决,尤其是在微软Windows上。于是开始了与Mozilla合作的一年内存分配工作。将jemalloc移植到Linux几乎微不足道,但Windows却不一样。当时jemalloc的源代码在FreeBSD的libc库中,所以我们基本上对jemalloc进行分叉,并添加了可移植性代码,将任何对FreeBSD相关的内容向上游提交。整个实现仍然在一个文件中,这减少了分叉维护时的摩擦,但该阶段的实现复杂性显然超过了合理范围。

多年后,Mozilla开发者为了摆脱他们的分叉,对上游的jemalloc做出了重大贡献。不幸的是,Mozilla的基准测试一直显示,分叉版本比上游版本表现得更好。我不确定这是因为对局部最优的过度拟合还是性能回归的真正迹象,但这是我对jemalloc最大的失望之一。

阶段2:Facebook

2009年我加入Facebook时,我惊讶地发现,阻碍jemalloc在Facebook基础设施中普遍使用的主要障碍是仪器设备。关键的内部服务陷入了尴尬的境地,它们依赖jemalloc来控制内存碎片,但工程师们需要使用tcmalloc和gperftools中的pprof堆分析工具来调试内存泄漏。pprof兼容的堆分析功能成为了jemalloc 1.0.0发布的主要亮点。

jemalloc开发迁移到GitHub,并在接下来的几年里随着问题和机遇的出现而继续进行。其他开发者也开始做出重要的功能贡献。3.0.0版本引入了广泛的测试基础设施以及Valgrind支持。4.x版本系列引入了基于衰减的清除功能和JSON格式的遥测。5.x系列从“块”转向“范围”,为更好地与2 MiB大页进行交互做好准备。

较为有争议的是,我在5.0.0版本中移除了Valgrind支持,因为这是一项重大的维护复杂性问题(在微妙的地方有很多分支),而且在Facebook内部未被使用;其他工具如pprof和MemorySanitizer占据主导地位。我几乎没有收到关于Valgrind支持的反馈,因此推断它未被使用。但回顾起来,这似乎并非如此。特别是,Rust语言直接将jemalloc整合到编译的程序中,而我认为Rust开发者和Valgrind开发者之间有某种重叠。人们感到愤怒。jemalloc可能比自然发展进程更快地被踢出了Rust二进制文件。

Facebook的内部遥测非常壮观,拥有各种服务的性能数据,这对内存分配器的开发是非常宝贵的。我不认为在过去的十年中,最快内存分配器之一(tcmalloc和jemalloc)受益于如此数据是巧合。即使是像快速路径优化这样的“简单”事情,当有汇总的Linux perf数据可用时,也更容易正确执行。像碎片管理这样的困难事情仍然困难,但如果数千种不同的工作流表现良好,没有异常的回归,那么更改可能是安全的。jemalloc在Facebook基础设施中受益匪浅,从性能、弹性到一致的行为。此外,jemalloc自身的集成统计数据报告功能正是应对这种普遍遥测环境而直接诞生的,这在实现上花费的精力不多,但对jemalloc开发和非Facebook应用程序的调优/调试普遍带来了巨大的好处。

在我在Facebook的最后一年,我被鼓励组建一个小的jemalloc团队,以便我们可以解决一些原本令人生畏的重要任务。除了重大的性能改进,我们还获得了持续集成测试和全面的遥测功能。当我2017年离开Facebook时,jemalloc团队继续出色地进行开发和维护工作多年,几乎完全不涉及我的参与,由我尊敬的同事王歧领导,并且从提交历史来看,也有许多其他人的出色贡献。

阶段3:Meta

在Facebook更名为Meta的时期,jemalloc的开发趋势明显发生了变化。Facebook基础设施工程减少了核心科技的投资,而是强调投资回报率。这在jemalloc的提交历史中显而易见。特别是,有原则的巨型页面分配(HPA)的种子早在2016年就已经埋下!HPA工作持续了几年,然后在不断的调整中放缓,并逐渐停滞,因为没有进行必要的重构来保持代码库的健康。这个特征路线最近崩溃了。对我而言,有些伤心,但我已经多年未密切参与,因此情感上的冲击被减弱了。但鉴于Meta内部近期的变化,我们现在没有人能推动长期的jemalloc开发,注重通用性。

我不打算深入讨论这些纷争,但也许值得一提的是,尽管涉及的大多数人都出于善意,但最终jemalloc在Facebook/Meta手中走向了令人遗憾的结局。企业文化会随着外部和内部压力而变化。而人们经常发现自己处于无法解决的困境中,主要的选择是1)在极端压力下做出糟糕的决定,2)在极端压力下服从,或者3)被绕开。作为个人,我们有时有足够的影响力来减缓组织的退化,甚至可能在局部复兴,但我们无法阻止不可避免的事情。

我仍然非常感激我的前同事在jemalloc上的所有优秀工作,以及Facebook/Meta对它投入了如此多资源、如此长的时间。

阶段4:停滞

现在怎么办?就我而言,“上游”的jemalloc开发已经结束。Meta的需求早已与外部使用的需求不一致,他们最好做自己的事情。如果我重新参与,第一步至少需要数百小时的重构以偿还累积的技术债务。而我对之后可能带来的东西并不足够兴奋以支付如此高昂的前期成本。也许其他人会创建可行的分支,无论是从dev分支还是从5.3.0版本(已经三年了!)。

在上述部分中,我提到了几个特定阶段的失败,但还有一些一般性的失败让我感到意外,尽管我的职业一直专注于开源开发。

如前所述,移除Valgrind引起了某些负面情绪。但问题的根本在于对其他使用和需求缺乏意识。如果我早知道它对任何人来说都重要,我可能会与其他人一起保留Valgrind支持。另一个例子是,我完全不知道jemalloc作为Android内存分配器的使用,可能有两年时间。而且,多年后,直到事后才知道它已被取代。
即使jemalloc完全公开在外部(没有在Facebook内部封存),该项目从未吸引到其他组织的主要贡献者。Mike Hommey推动Firefox迁移到上游jemalloc的努力是一个差一点的成功。其他人试图迁移到基于CMake的构建系统也多次失败,从未完成。我从与Darwin硬碰硬的经验中知道,内部封存的开源项目无法繁荣(HHVM是一个重复的例子),但jemalloc作为一个独立项目,需要的不只是开放开发。

对我而言,jemalloc是一项奇特的分心,因为我长期以来一直是垃圾收集的坚定支持者,而不是手动内存管理。我个人很高兴再次投入到垃圾收集系统中,但jemalloc是一个令我非常满足的项目。感谢所有让这个项目变得如此有价值的人,包括合作者、支持者和用户。

原文链接:https://www.oschina.net/news/361911
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章