Claude 11天重写Bun 创始人一个月才敢交底
时间:2026-07-19 11:15
2026年5月,Bun项目在11天内借助Claude将53万行Zig代码重写为Rust,花费16 5万美元API费用。重写后内存占用从6 7GB降至609MB,修复128个bug,但引入了约13000个unsafe代码和19个已知回归问题。代码依赖AI审查,人类无法逐行阅读全部变更。
2026年5月,Bun项目实现了一次在软件开发史上堪称里程碑的大规模代码迁移。这场迁移从5月3日启动,到5月14日正式合并入主分支,仅用了11天。实际编写代码只用了6天,整个过程完全公开。但项目负责人Jarred Sumner撰写博客总结却花了将近一个月——比写代码的时间还要长得多,这本身就很能说明问题。
该JavaScript运行时原本包含535,496行Zig代码(不含注释),同时约有20%的代码由C++编写,并嵌入了多个C/C++库。此次借助AI重写为Rust,涉及超过100万行代码变更、6778次提交,并在Claude Code中运行了大约50个动态工作流。
据Sumner披露的数据,此次重写在API层面消耗了59亿个未缓存输入token、6.9亿个输出token,以及720亿个缓存输入token读取,按API定价计算,总花费约16.5万美元。
Sumner指出,这已是当前技术所能达到的前沿水平。他估算,若由3名完全熟悉Bun代码库的工程师手工完成此次迁移,大约需要一年时间,且在此期间团队几乎无法继续推进新功能开发、bug修复和安全修复。
重写之后,Bun v1.3.14成为最后一个Zig版本,而Bun v1.4.0将成为首个Rust版本。
1 成果:内存泄漏由6.7GB降至609MB,系统更稳定
Bun最初是一个Zig项目,覆盖面极广:它既是JavaScript和TypeScript转译器,也是打包器、包管理器、测试运行器、模块解析器、HTTP和WebSocket客户端,还实现了Node.js API层。正是这种产品宽度,使得Bun的CLI月下载量超过2200万次,并获得了Vercel、Railway、DigitalOcean、Claude Code和OpenCode等项目或公司的支持。
然而,同一枚硬币的另一面,是这种宽度给Bun带来了一些棘手的挑战。
特别是在Bun v1.3.14中,有一个令团队头疼已久的问题:连续执行Bun.build()调用时,内存会不断累积,永不释放。每次构建大约泄漏3MB,看似不多,但如果你运行的是一个开发服务器,每次请求都触发一次构建,那么内存就会被一点点吞噬,直到进程崩溃。
在实际测试中,执行500次构建后内存占用1.9GB,1000次后3.5GB,1500次后5.1GB,2000次后飙升到6.7GB。

这仅仅是诸多内存问题的冰山一角。在v1.3.14的bug修复清单中,Sumner列出了一长串问题:
> zlib模块里调用.reset()时,如果还有一个异步.write()正在线程池中执行,进程就会因“堆释放后使用”而崩溃;http2模块里嵌套的JavaScript回调触发了哈希表重哈希,导致内部流指针失效;UDPSocket.sendMany()在遍历过程中,如果用户代码通过valueOf或toString回调改变了套接字的连接状态,就会发生越界写入;crypto.scrypt在输出缓冲区分配失败时,回调和受保护的密码缓冲区永远得不到释放;……
这些bug的共性非常明显,几乎都指向同一个根源——将GC与手动内存管理混用。
JavaScriptCore(以及V8)这样的现代引擎对异常处理和GC有极其严格的规则,而Zig像C语言一样不会自动管理内存。当这两种范式在同一个进程中并存时,每个内存分配都需要被逐行审查:这些字节在哪里被释放?如何确保只释放一次?是否正确检查了JavaScript异常?这个被GC管理的指针对保守栈扫描器可见吗?这是GC内存还是手动管理的内存?
更令人焦虑的是,团队并非没有努力。他们已经给Zig编译器进行了修改,添加了Address Sanitizer支持(ASAN),每次提交都在CI中运行ASAN测试,在Windows上使用ReleaseSafe构建,用Fuzzilli做24/7的模糊测试,还有大量端到端的内存泄漏测试。即便如此,崩溃报告仍然源源不断。
“我们的bug修复列表让人感觉很糟糕,我厌倦了带着对Bun崩溃的担忧去睡觉。”Sumner写道。他并不责怪Zig——其他Zig用户并没有遇到Bun这样的问题,因为将GC与手动管理内存混合使用,本身就是一种极罕见的需求,几乎没有语言为此设计。
而Rust版本交出的答卷是:同样执行2000次Bun.build(),内存稳定在609MB。
除了内存泄漏问题得到根本性解决,Rust重写还带来了其他几个维度的改善。
在稳定性方面,v1.4.0修复了v1.3.14中可复现的128个bug,从内存泄漏到崩溃到颜色显示错误的帮助文本都得到了解决。
从体积上,结合Rust重写、ICU更改和相同的代码折叠,Bun在Linux和Windows上的二进制文件大小减少了约20%。

在性能方面,普遍提升了2%到5%。Bun.serve从16.96万req/s提升到17.77万req/s,node:http从10.38万提升到10.85万。实际应用场景中,next build从13.62秒降至13.03秒,tsc批量编译从0.94秒降至0.89秒。
而Claude Code在基于Rust的Bun发布后,Linux上的启动时间从517ms降至464ms,快了约10%。
2 方法:64个Claude并行,11天,50个工作流
Sumner是怎么做到的,这可能是最值得关注的部分——因为他用的方法,与传统的“让AI写代码”完全不同。
Sumner把整个过程拆成了大约50个动态工作流,每个工作流都是一个循环。他在博客里用伪代码描述了这个模式:

每个任务都有一个上下文(比如一个Jira ticket或GitHub issue),Claude基于这个上下文写出代码,然后两个审查者(也是Claude)审查代码,最后应用反馈。完成之后,再取下一条任务。
这种模式贯穿了整个重写过程。每个工作流负责一个特定目标:
- 生成一份porting guide,将Zig的模式和类型映射到Rust的模式和类型;
- 把每个.zig文件机械式移植成一个.rs文件,并匹配PORTING.md和LIFETIMES.tsv;
- 修复每个crate的编译错误;
- 让bun test或bun build这样的子命令跑起来;
- 让Bun整个测试套件里的每个测试都通过;执行几轮大型重构和清理。
在峰值时期,Sumner同时运行了4个工作流,每个工作流里16个Claude,总共64个Claude同时在4个工作树中并行工作,各自提交和推送文件。在最高峰时,Claude每分钟写了约1300行代码。
这种“实现者/审查者”的分离设计是关键。写代码的Claude想让代码被接受,这和人类工程师一样有偏见。所以审查者和实现者完全分开——审查者只看代码差异,不看实现者的推理过程,而且被明确告知“假设代码是错的”。每个实现者对应两个以上的对抗性审查者,审查者的唯一工作就是找bug。

代码写完只是第一步。Zig代码是单一编译单元,而Rust要拆分成约100个crate来加快编译速度,循环依赖导致cargo check一次性输出约16000个编译错误。对于一个人来说这是灾难,但对于64个并行工作的Claude来说,这是可以处理的工作队列。工作流把错误按crate分组,每个crate跑一遍cargo check,一个Claude修复,两个审查,一个应用修改。
接下来是让bun --version跑起来,然后是bun test。测试工作流每次随机跑100个测试文件,分片到4个工作树。测试套件也包含好几种:有些测试会运行超过一分钟,有些会耗尽系统TCP连接数,有些会fork约10000个进程。Sumner用systemd-run创建cgroup来限制资源,但机器还是因为磁盘空间不足崩溃了好几次。
两天后,Linux平台的失败测试从972个降到了23个。一天半之后,Linux全绿了。五天后,全部六个平台——Linux x64、Linux arm64、macOS x64、macOS arm64、Windows x64、Windows arm64——全部通过。
5月14日,PR#30412正式合并,测试套件全部通过,没有跳过或删除任何测试。
3 隐忧:13,000个unsafe关键字与无法逐行审查的代码
不过,Sumner也承认,这项工作还没有真正结束。
截至目前,Bun的Rust代码中大约有4%位于unsafe block内,约13,000个unsafe关键字,分布在约27,000行代码中,而Rust总代码量约为780,000行。其中78%的unsafe block只有一行,通常是一个来自C++的指针,或者一次对C库的调用。
他预计后续重构会让这个比例降下来。但有人算了一笔账:uv约35万行代码,只有73次unsafe调用。而Bun的unsafe数量是uv的178倍。这个差距很难用“需要调用C库”来解释。
更棘手的是,随后还在安全Rust代码中也暴露了未定义行为。这比C++还难调试,因为你会以为安全代码不可能出问题。

Bun团队随后将这个问题中的PathString::init改成了unsafe fn。
Sumner自己也承认,这次重写引入了19个已知的回归问题,并表示大多数回归问题都源于语法相同但语义不同的代码。

比如这两个代码片段看起来相似,但行为却截然不同。Zig的代码assert是一个函数,因此它的参数在每次构建中都会运行。Rust的代码debug_assert!是一个宏,因此在发布版本中,整个表达式(包括函数调用)都会被删除insert_stale。
虽然这些问题已经修复,但这并不表示百万行AI代码就没有其他问题。

> 正常人谁会在一个运行时被彻底重写之后,立刻把自己的生产应用迁过去?如果以为1.4版本没有引入新的bug,或者没有带来行为变化,那就太天真了。
还有一个不能忽略的事情是代码审查。100万行的变更实际上没法由人类逐行看——就算一分钟看一行,也要连续看11.7天;按实际的代码审查速度(一小时200行),要两年多才能看完。
这次PR的审查者主要是claude[bot]和coderabbitai[bot]。Sumner自己也承认,他的审查方式是“检查对抗性审查agent是否正确捕获了差异,确保转换指南被遵守,同时自己也手动读了不少代码”。但“不少”是多少,他没有说。
还有一个绕不开的问题:Bun在2025年12月被Anthropic收购了,真正能有效维护这套代码库的工具,基本只有Claude自己。社区里有人说,这已经算不上传统意义上的开源项目了——你想给Bun提PR,得先订阅Anthropic,或者指望那几个已经看懂了AI生成代码的核心成员。
16.5万美元换一年工作量,值吗?
Sumner在博客中还披露,这次重写的API成本约为16.5万美元,等于3名工程师一年的工作量。这个数字在Hacker News上引发了激烈的讨论。
有人认为,这笔账其实很划算。16.5万美元在硅谷请不了几个全职工程师,更不用说Anthropic这种级别公司的工程师了。按照levels.fyi上的薪资数据,Anthropic工程师的总包很可能达到50万美元甚至更高。即便按50名工程师平均年薪33.6万美元粗略计算,折合到每天大约是1292美元。50个人连续工作11天,光人力成本就已经接近71万美元,还不包括福利、办公场地、设备和其他管理开销。

但是,Sumner使用的是“Claude Fable 5的预发布版本”,一个尚未对公众开放、可能受出口管制的高阶模型。所以API定价只是最终用户看到的数字,背后是Anthropic投入的巨额研发费用。还有人指出,把成本简化成API定价,是在刻意淡化真实投入。如果算上模型研发成本、训练成本、算力投入、工程人力等,最终的总成本很可能很高,甚至超过150万美元。

而且目前看来,虽然16.5万美元换一年工作量,账面上看挺划算。
但真正的成本不在这张账单上。这个代码库有6778次提交,没有一个人从头到尾完整读过。虽然眼下一切正常,可六个月后呢?当某个诡异的并发问题在凌晨三点突然冒出来,负责值班的工程师面对的是一个连他自己都说不清内部逻辑的系统。延伸到以后都得AI来维护,维护成本怎么算,其实挺难。
**参考链接:**
https://bun.com/blog/bun-in-rust
https://hn.edgecompute.app/item/48837877