一、Bun v1.4.1 说了什么?
先看这个版本的核心变化。按影响力排序:
闲置内存回收:JIT 代码的"自杀式"优化
JavaScriptCore 现在会在进程闲置一段时间后,删除 JIT 生成的机器码。这意味着一个 Next.js SSR 应用在负载后闲置 3 分钟,RSS 从 1,303 MB 骤降至 142 MB——降幅接近 11 倍。
这不是魔法,而是 JSC 的 LLInt → Baseline JIT → DFG → FTL 四级编译管道在闲置时被主动清空。V8 不会这么做:它为长驻留进程设计,JIT 热代码会一直保留。Bun 反其道而行——"用完即焚",因为它的目标场景包括 CLI 工具、Serverless 函数和短生命周期进程。
<span>Bun</span> v1.<span>4.1</span> 闲置内存基准(<span>Linux</span> x64,60s 负载 + <span>3</span> 分钟空闲):
|<span> 应用 </span>| <span>Bun</span> v1.<span>4.1</span> |<span> Bun v1.4.0 </span>| <span>Bun</span> v1.<span>3.14</span> |<span> Node.js v26 </span>|
|<span>-------------</span>|-----------<span>:|-----------</span><span>:|------------</span><span>:|------------</span><span>:|</span>
|<span> Next.js SSR </span>| <span>142</span> <span>MB</span> |<span> 222 MB </span>| <span>1</span>,<span>303</span> <span>MB</span> |<span> 195 MB </span>|
|<span> vite dev </span>| <span>111</span> <span>MB</span> |<span> 142 MB </span>| <span>292</span> <span>MB</span> |<span> 115 MB </span>|
|<span> Express </span>| <span>53</span> <span>MB</span> |<span> 65 MB </span>| <span>76</span> <span>MB</span> |<span> 83 MB </span>|
|<span> Fastify </span>| <span>55</span> <span>MB</span> |<span> 65 MB </span>| <span>78</span> <span>MB</span> |<span> 89 MB </span>|
|<span> Hono </span>| <span>34</span> <span>MB</span> |<span> 35 MB </span>| <span>53</span> <span>MB</span> |<span> 92 MB </span>|
HTTP/2 首次入原生运行时
Bun.serve 现在在同一端口上同时支持 HTTP/2 和 HTTP/1.1——通过 ALPN 协商。基准测试显示,Bun 的 HTTP/2 实现比 Node.js 的 node:http2 快 6.8 倍(Hello World GET:291,512 vs 55,619 req/s)。
但真正的故事不在这里。
Bun.write(path, response):流式写盘
Bun.write() 现在直接将 Response、Request 或 ReadableStream 体写入磁盘,而不是先读入内存。写入一个 128 MiB 的下载,峰值 RSS 从 161 MB 降至 13 MB。
这是一个架构选择:它意味着 Bun 的 I/O 路径设计从一开始就考虑了零拷贝和背压,而不是事后修补。
其余关键变化
- WebSocket
pause()/resume():WHATWG WebSocket API 无法暂停接收消息而不关闭连接。Bun 扩展了这个 API,允许在消息到达速度快于处理速度时施加 TCP 背压。 crypto.argon2:Argon2 密码哈希现在原生支持,输出与 Node.js 逐字节一致。- Buffer 读写 9x 加速:
writeFloatLE()从 2.85ns 降至 0.31ns——JIT 内联边界检查后的直接加载/存储。 bun build --compile --bytecode跨平台交叉编译:字节码缓存格式现在在所有平台一致,Claude Code 的安装包从 376 MB 缩减到 207 MB(-45%)。
二、但真正的头条不在上面
Bun v1.4.1 发布 13 天前,Bun v1.4.0 于 2026 年 8 月 20 日发布。这是第一个用 Rust 写的 Bun,也是最后一个用 Zig 写的 Bun(v1.3.14)之后的第一个版本。
时间线:
| 日期 | 事件 |
|---|---|
| 2026-05-13 | Bun v1.3.14 发布,最后一个 Zig 版本的运行时 |
| 2026-05-14 | Rust 端口合并到 `main` 分支 |
| 2026-05-14 ~ 08-20 | 3 个月沉默期,修复回归 |
| 2026-08-08 | Jarred Sumner 发布《Rewriting Bun in Rust》 |
| 2026-08-20 | Bun v1.4.0 发布,Rust 运行时首次稳定 |
| 2026-09-04 | Bun v1.4.1 发布,202 个问题修复 |
从最后一份 Zig 代码到稳定版 Rust 运行时,只用了 11 天。 不,准确地说——是 64 个 Claude 代理并发工作了 11 天,留下了 6,778 个提交和一个超过 100 万行代码的 diff。
三、为什么是 Zig?——Bun 的原始选择
要理解为什么这场迁移如此震撼,需要回到 Bun 的起点。
Zig 的诱惑
Bun 的创造者 Jarred Sumner 在 2021 年选择 Zig 作为运行时语言,绝非偶然。Zig 有几个特性精准命中了 Bun 的设计需求:
- 手动内存管理,没有隐藏控制流:没有 GC 暂停,没有异常展开(exception unwinding),每一笔分配都清晰可见。这对追求极致性能的 HTTP 服务器至关重要。
- C 互操作性一等公民:Bun 需要嵌入 JavaScriptCore(C++),Zig 与 C 的互操作比 Rust 更直接。
- comptime(编译时计算):零成本抽象,可以在编译期做大量工作而不运行时付费。
- 错误处理模型:
errorunion 强制开发者处理所有可能的失败路径,没有try/catch的运行时开销。
Bun 的架构因此分成两层:
- JavaScriptCore(C++):执行 JavaScript 字节码
- Zig 运行时:HTTP 服务器、包管理器、文件系统、I/O 层
Zig 运行时替代了 Node.js 的 libuv。直接使用 Linux 的 io_uring(内核 5.1+ 的异步 I/O 接口)、macOS 的 kqueue,绕过线程池的传统瓶颈。
Bun 原始架构(v1.3.14 及之前):
┌──────────────────────────────┐
│ JavaScriptCore │ ← C++,Safari 的 JS 引擎
│ (LLInt / Baseline / DFG/FTL) │
└──────────┬───────────────────┘
│
┌──────────▼───────────────────┐
│ Zig 运行时 │ ← 手动内存管理
│ ┌─────────────────────────┐ │
│ │ io_uring / kqueue │ │ ← 原生异步 I/O
│ │ arena allocators │ │ ← 每请求分配批量释放
│ │ HTTP 服务器 / 包管理器 │ │
│ │ bun build / bun <span>test</span> │ │
│ └─────────────────────────┘ │
└──────────────────────────────┘
这个架构在性能上取得了惊人的成功。Bun 的冷启动速度、包管理器速度、测试运行速度都远超 Node.js。
但问题也随之而来。
Zig 的代价
手动内存管理是双刃剑。Bun 的代码库中,use-after-free 和 double-free 漏洞如影随形。正如 Jarred Sumner 在《Rewriting Bun in Rust》中所写:
"历史上,语言重写是个糟糕的主意。Bun 不含注释有 535,496 行 Zig 代码。用另一种语言重写需要一个小团队工程师花一整年。这意味着冻结 bug 修复、安全补丁和功能开发整整一年。"
但 Anthropic 在 2025 年 12 月收购了 Bun。资金充裕,AI 工具成熟,窗口期打开。
四、为什么转向 Rust?——内存安全的诱惑
Rust 的核心卖点是所有权模型:编译器在编译期保证内存安全,没有 GC,没有 use-after-free,没有数据竞争。
对于 Bun 来说,这个迁移的理由很明确:
- 消除内存安全漏洞:Zig 的 use-after-free 和 double-free 问题在长期运行的服务中尤其危险。Rust 的所有权模型在编译期捕获这类错误。
- 更好的并发原语:Rust 的
Send+Synctrait 在类型层面保证了线程安全。 - 生态系统:Rust 的 crate 生态在系统编程领域已经相当成熟。
但这里有一个关键争议——性能是否因此提升?
性能争议的罗生门
Bun 官方将 2-5% 的速度提升归因于跨语言链接时优化(LTO)——Rust 和 C++ 引擎之间的链接优化。但 Andrew Kelley(Zig 语言的创造者)在 2026 年 7 月 9 日发表了尖锐批评:
"性能提升归因于 LTO,而 Zig 在 Bun 的整个生命周期中都支持 LTO。"
独立开发者 Dennis Morello 进一步指出:
"2-5% 的速度提升和约 20% 更小的二进制文件,来自跨语言 LTO、ICU 裁剪和链接器工作——这些在 Zig 中也能做到,不是 Rust 语言的功劳。"
真正的大幅性能提升——闲置 CPU 降低 5 倍、内存降低 13-48%——来自另一个变化:将 JavaScriptCore 统一到 mimalloc 分配器,取代了之前 libpas 和 mimalloc 并行的方案。这不是语言选择的功劳,而是内存分配策略的优化。
换句话说:Rust 迁移的性能收益被夸大了,真正的原因是架构调整和内存管理优化。
五、64 个 Claude 代理的 11 天
这是整个故事中最超现实的章节。
Jarred Sumner 披露:
- 64 个 Claude 代理并发工作
- 11 天完成端口
- 6,778 个提交
- +1,009,272 行 diff
- 约 $165,000 的 API token 花费
- 19 个已知回归,全部已修复
端口的方法论是"强制代码风格":不是纯粹的机械翻译,而是用代码风格规则确保生成的 Rust 代码行为一致。测试套件是唯一的真理标准——所有平台、所有测试通过,零跳过。
开发者 Tero Piirainen 在发布前审查了仓库,发现:
- robobun 账户单月 15,800 个提交
- 自动修复机器人 1,600 个提交
- Bun 负责人 790 个提交
- 超过 5,000 个开放 PR
他还指出,Rust 代码中约 4% 包含 unsafe 块——约 13,000 个 unsafe 关键字分布在约 27,000 行代码中。如果 4% 的代码是不安全的,那"内存安全"的叙事还剩多少说服力?
这是整个迁移中最深刻的悖论:为了内存安全而重写的代码,仍然需要 unsafe 来突破安全边界。
六、Bun 的技术架构:JavaScriptCore + Rust
理解 Bun v1.4.1 的关键,是理解它的分层架构没有改变:
Bun v1<span>.4</span><span>.1</span> 架构:
┌────────────────────────────────────┐
│ JavaScriptCore │ ← 未变,C++ 引擎
│ (约 <span>400</span> 个上游 WebKit 提交) │
│ LLInt / Baseline / DFG / FTL │
└──────────────┬─────────────────────┘
│
┌──────────────▼─────────────────────┐
│ Rust 运行时 │ ← 从 Zig 迁移
│ ┌──────────────────────────────┐ │
│ │ HTTP 服务器 (Bun.serve) │ │ ← io_uring + epoll/kqueue
│ │ bun install (包管理器) │ │ ← 全局缓存 + 硬链接
│ │ bun build (打包器) │ │ ← 基于 esbuild 的 Rust 重写
│ │ bun test (测试运行器) │ │ ← Jest 兼容
│ │ bun:sqlite / bun:redis │ │ ← 内置客户端
│ │ 文件系统 / I/O 层 │ │ ← 零拷贝路径
│ └──────────────────────────────┘ │
│ │
│ ⚠️ 约 <span>4%</span> unsafe 块 │
└────────────────────────────────────┘
JavaScriptCore 本身没有变。变的是围绕它的运行时层:HTTP 服务器、包管理器、打包器、测试运行器、文件系统层——所有用 Zig 写的都换成了 Rust。
七、Bun vs Node.js vs Deno:2026 年的运行时三国杀
| 维度 | Bun v1.4.1 | Node.js 26 | Deno |
|---|---|---|---|
| JS 引擎 | JavaScriptCore | V8 | V8 |
| 运行时语言 | **Rust** | C++ | Rust |
| Node 兼容目标 | Node 26.3.0 | 完整 | 部分 |
| `NODE_MODULE_VERSION` | 147 | 147 | - |
| 包管理器 | 内置 `bun install` | npm | `deno` |
| 打包器 | 内置 `bun build` | 外部 | 外部 |
| 测试运行器 | 内置 `bun test` | `node:test` | `deno test` |
| 数据库客户端 | 内置 (PG/MySQL/SQLite/Redis) | 外部 | 外部 |
| 冷启动 | ~5ms | ~50ms | ~30ms |
| 闲置内存 | **最低** | 中等 | 中等 |
| 原生插件 | 部分 N-API | 完整 | 有限 |
| LTS | 无 | 30 个月 | 无 |
| 企业背书 | **Anthropic** | OpenJS Foundation | 独立 |
关键洞察:
- Bun 和 Deno 现在都是 Rust,但 Bun 选择了 JavaScriptCore 而不是 V8。这才是性能差异的主因,不是语言本身。
- Node.js 26 进入了 LTS(2026 年 10 月至 2029 年),这是保守派的选择。
- Bun 的 Node 兼容度已接近可用:
node:events、node:trace_events、node:sqlite100% 通过 Node 官方测试,node:http、node:fs等核心模块约 97%。但那剩下的 3% 恰恰是最棘手的问题。
八、深度思考:AI 辅助重写是未来还是危险先例?
Bun 的 Rust 迁移打开了一个潘多拉魔盒。
如果 64 个 AI 代理能在 11 天内完成一个运行时核心的语言迁移,那么:
- 软件工程的生产力边界在哪里?
- 代码审查的意义是什么?(19 个回归——AI 生成的代码需要人来发现)
- "AI 程序员"和"AI 编码助手"的区别是什么?
Jarred Sumner 的回应很诚实:
"这次重写引入了 19 个已知回归,每一个都已修复。聚焦于稳定性是目标,但如此庞大的变更不可能零回归。"
更有趣的是 Claude Code 本身——Anthropic 的编程工具——已经用 Bun 的 Rust 端口在生产环境中运行。它的 p99 CPU 从 24% 降至 10%。
**Anthropic 收购 Bun → 用 Claude 重写 Bun → Claude Code 在 Bun 上运行 → Bun 的性能数据证明 Anthropic 的技术栈优势。**这是一个闭环。
九、总结:这篇 v1.4.1 文章的真正意义
Bun v1.4.1 的 202 个修复看起来像是一次常规更新。但如果你理解了 11 天前那场语言迁徙的规模和争议,就会明白:
- 闲置内存回收不是 Bug 修复,是架构选择的结果——JavaScriptCore 的 JIT 代码按需生成和销毁,这是 Bun 从一开始就坚持的设计哲学。
- HTTP/2 原生支持是 Rust 运行时带来的新能力,因为 Zig 版本的代码库在迁移期间被冻结,新 API 只能在新的 Rust 代码上实现。
Bun.write()流式写盘反映了底层 I/O 路径的重构——Rust 的异步模型让零拷贝管道更容易实现。- 跨平台字节码交叉编译是 Rust 平台的统一格式带来的红利——字节码缓存格式现在在所有平台一致。
Bun v1.4.1 的每一个技术亮点,背后都有 Rust 迁移的影子。
而更宏大的叙事是:JavaScript 运行时已经不再是 C++ + V8 的天下。Rust + JavaScriptCore 的组合正在挑战 Node.js 的王座,代价是 4% 的 unsafe 和 19 个已知回归。
这是 2026 年最精彩的系统编程故事。
原创技术博客 · 开源项目架构深潜 · idao.fun
对关注 AI 辅助大规模重构与运行时选型的团队,这篇复盘值得细读:它提醒我们别把语言当性能银弹,也别忽视 AI 生成代码的审查成本与 unsafe 风险。