
本文永久链接 – https://tonybai.com/2026/06/30/rust-project-eating-75gb-disk-space-go-vs-rust-cache-anxiety
大家好,我是Tony Bai。
在系统级编程的世界里,开发者们似乎永远在为两件事焦虑:一是代码能不能编译通过,二是编译究竟要花多长时间。
为了解决第二个问题,现代编译器进化出了极度贪婪的“胃口”。它们在你的本地疯狂下载依赖、保存中间产物、缓存增量编译结果——用一种近乎粗暴的方式,拿你的物理硬盘空间,去换取你生命中的几秒钟编译时间。
最近,在 Reddit 的 r/rust 社区, 一位开发者发帖求助:《我的 Rust 工作区(Workspace)达到了 75GB,对于长期项目来说,这正常吗?》 ,这个经过几个月开发的项目,其 target 目录已经被塞得满满当当。

原以为大家会帮他排查问题,没想到评论区瞬间变成了“比惨大会”和“凡尔赛现场”:
- “老弟,才 75G?一切正常。我刚敲了一行
cargo clean,清出了 300GB 空间,感觉整个人都升华了。” - “我的记录是 1TB 的纯缓存,因为里面存了 300 个表的数据库crate 增量编译结果……”
- “为了回答你这个问题,我专门买了一块新的 2TB 固态硬盘,只为了写 Rust。”
面对这种夸张的“磁盘吞噬战”,无论是深陷 target 泥潭的 Rust 玩家,还是常年看着 GOMODCACHE 日益膨胀的 Go 语言开发者,都患上了严重的“缓存焦虑症”。
今天,我们就来深度剖析一下:为什么现代编译器变得如此贪吃?我们又该如何通过社区的黑科技与官方的底层机制,拯救我们奄奄一息的固态硬盘?

病理分析:为什么 Rust 和 Go 都在疯狂吞噬你的硬盘?
虽然最终结果都是“磁盘空间不足(Disk Full)”,但 Rust 和 Go “吃硬盘”的姿势和底层逻辑却截然不同。
1. Rust 的空间黑洞:局部而疯狂的 target/ 目录
在 Rust 中,万恶之源就在你项目根目录下的那个 target/ 文件夹。如果你用 du -sh target/ 查看一下,你大概率会被那个数字吓倒。
Rust 极其贪吃的原因有三个:
- 重复编译的孤岛效应:默认情况下,Cargo(Rust 的包管理器)是按**项目局部(Per-project)**管理编译产物的。这意味着,如果你有 10 个独立的项目都依赖了
tokio和serde,那么这 10 个项目会各自在自己的target/目录下把这两个庞然大物重新编译一遍,并保存中间件。 - 增量编译与环境矩阵:每次你修改一行代码,Rustc 为了加快下次编译的速度,会生成大量的增量文件。更要命的是,
dev模式、release模式、甚至你切换了一次 Rustc 的版本(比如从 1.94.0 升到 1.95.0),旧版本的编译构件(Artifacts)都不会被自动删除,而是层层叠加。 - 庞大的调试符号(Debug Symbols):在默认的开发模式下,Rust 会生成极其详尽的调试信息,这些信息的大小往往是最终二进制文件的十倍甚至百倍。
2. Go 的隐秘仓库:全局膨胀的 pkg/mod 与 GOCACHE
相比之下,Go 的设计哲学显得更为全局观,但同样不可避免地会随着时间的推移而“发福”。
自 Go Modules 普及以来,Go 放弃了基于项目局部的 vendor 目录,转而将所有依赖都下载到了一个全局的、不可变的目录中(通常是 ~/go/pkg/mod)。
- 只增不减的 Module 仓库:这种设计的好处是:10 个项目共用同一个依赖版本,硬盘上只存一份源码。但坏处是,随着你接手的项目越来越多,各种依赖的历史版本(v1.1, v1.2, v1.5…)会不断堆积,Go 默认并不会自动删除这些旧代码。
- 深藏功与名的构建缓存:为了实现标志性的“秒级编译”,Go 在后台默默维护了一个全局的构建缓存目录(可通过
go env GOCACHE查看)。这里面塞满了编译过的包对象(.a文件),这让你在修改自己的代码时,不需要重新编译标准库和第三方库。
拯救行动:Rust 玩家的“续命指南”
对于被 target 目录折磨的 Rustacean 来说,生存策略可以分为“毁灭性打击”和“精准优化”两种。
1. 物理毁灭:cargo clean
这是最解压的命令。敲下 cargo clean,几百 GB 的空间瞬间释放。
但代价是惨痛的——下次编译时,你将不得不花上几十分钟盯着屏幕上的 Compiling xxx 进度条发呆。这属于典型的“爽一时,痛一天”。
2. 精准外科手术:社区的极客神器
为了不把洗澡水和孩子一起倒掉,Reddit 上的老手们推荐了一系列神器:
cargo-sweep:这是一个极其优雅的插件。你可以用cargo sweep --installed清理掉那些属于旧版本编译器的残留构件;或者用cargo sweep --time 30删掉过去 30 天都没有被访问过的僵尸文件。sccache:这是由 Mozilla 开发的神器,相当于 C/C++ 世界的ccache。它不仅能接管编译缓存,还能在多个不相关的 Rust 项目之间共享相同的依赖编译结果。当你开启sccache后,那些重复的tokio编译噩梦将不复存在。kondo:如果你是一个全栈开发者,电脑里混杂了大量的 Rust、Node.js (node_modules) 和 Go 项目。这个命令行工具可以一键帮你递归扫描并清理所有项目的构建垃圾。
3. 架构级调优:全局共享 Target
许多拥有多个相关 Rust 仓库的开发者,会在 ~/.cargo/config.toml 中配置全局的 build.target-dir。
[build]
target-dir = "/path/to/global/target"
这样,所有的项目都会把编译产物丢进同一个大池子里。虽然这个池子依然会变大,但至少你享受到了跨项目的依赖复用红利。
Go 团队的底层降维打击:从自动老化到可编程缓存
与 Rust 社区依靠丰富的第三方插件进行“自救”不同,Go 语言的解决方案往往带有强烈的“官方统筹”与“工程极简”色彩。
在依赖与缓存管理上,Go 官方其实在底层布下了多道防线,甚至开放了极其前沿的黑科技。
1. 自动老化的全局 GOCACHE
不同于 Rust 那个只要你不删就永远存在的 target 目录,Go 的 GOCACHE 机制自带了一个非常克制的自动垃圾回收(GC)机制。
Go 会自动跟踪缓存项的最近使用时间(mtime)。Go 命令在退出时,会检查距离上次清扫是否已超过 1 天,若是则触发一次扫描,删除那些超过 5 天未被访问的构建缓存条目。这也是 Go 开发者很少会遇到单一缓存目录膨胀到几百 GB 的原因。
// $GOROOT/src/cmd/go/internal/cache/cache.go
// Time constants for cache expiration.
//
// We set the mtime on a cache file on each use, but at most one per mtimeInterval (1 hour),
// to avoid causing many unnecessary inode updates. The mtimes therefore
// roughly reflect "time of last use" but may in fact be older by at most an hour.
//
// We scan the cache for entries to delete at most once per trimInterval (1 day).
//
// When we do scan the cache, we delete entries that have not been used for
// at least trimLimit (5 days). Statistics gathered from a month of usage by
// Go developers found that essentially all reuse of cached entries happened
// within 5 days of the previous reuse. See golang.org/issue/22990.
const (
mtimeInterval = 1 * time.Hour
trimInterval = 24 * time.Hour
trimLimit = 5 * 24 * time.Hour
)
2. 清理指令
如果你真的硬盘见底了,Go 也提供了两个极其安全的一键清理指令:
go clean -cache:清空编译缓存(和Rust一样,下次编译会变慢,但不会丢失源码)。go clean -modcache:清空下载的全局 Module 依赖源码(下次编译会重新联网下载代码)。
3. 前沿黑科技:GOCACHEPROG 协议的无限想象
这是 Go 1.21 以实验性功能引入、并在 Go 1.24 正式稳定的一个鲜为人知、但极具颠覆性的环境变量——GOCACHEPROG。
在过去,构建缓存只能老老实实地写在本地硬盘上。但 Go 团队意识到,对于大型微服务团队和 CI/CD 平台来说,局部的硬盘缓存已经满足不了需求了。
通过实现 GOCACHEPROG 接口,开发者可以编写一个独立的、与 Go 编译器通信的外部程序,彻底接管缓存的读取与写入逻辑!
这意味着什么?
- 你可以写一个 Go 程序,把编译缓存直接写进公司的 Redis 集群或者 AWS S3 存储桶中。
- 整个公司的所有开发者、以及所有的 CI 构建流,都可以实时共享同一个远程编译缓存池。一个人编译了某个底层库,全公司受益!这不仅彻底拯救了所有人的本地硬盘,更是将大型项目的构建速度推向了理论极限。
4. 未来展望:Module 缓存的极致压缩
对于Go mod cache的膨胀问题,Go 的社区目前也在积极探讨对 pkg/mod 目录的物理优化,包括希望提供module 的remove命令来支持手动删除Go module cache目录下的某个版本的go module。
由于解压后的 Module 源码包含大量的碎小文件,这会极其消耗 Linux 系统的 inode 资源和磁盘空间。社区中已有第三方工具(如 Tailscale 开源的 gomodfs)探索以 FUSE/NFS 方式将 zip 格式的依赖包直接挂载为文件系统,从而避免解压带来的磁盘和 inode 开销。
小结:空间与时间的永恒博弈
从 Reddit 上的“75GB 惨案”,到各大语言社区绞尽脑汁的缓存优化,我们看到的是软件工程学中最经典的博弈:空间换时间。
编译器是聪明的。它知道程序员的薪水(时间)比固态硬盘要昂贵得多。所以,它宁愿被骂作“硬盘杀手”,也要尽可能把一切中间状态缓存下来,只为了在你按下 Ctrl+S 的那一刻,能以最快的速度把报错信息拍在你脸上。
幸运的是,无论是 Rust 社区诸如 sccache 的极客工具,还是 Go 语言底层开放的 GOCACHEPROG 协议,都在向我们证明:随着云原生和分布式编译的演进,我们终将打破单机物理硬盘的桎梏。
最后,敲下这篇文章时,我默默看了一眼我的 ~/.cargo/ 和 ~/go/ 目录。
那么,正在阅读这篇文章的你,敢不敢在终端里输入一行 du -sh,在评论区晒出你的“硬盘惨案”呢?
资料链接:https://www.reddit.com/r/rust/comments/1ufaef8/my_rust_workspace_is_75gb_is_this_normal_for/
还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 《从0 开始构建 Agent Harness》 将带你:
- 抛弃臃肿框架,回归“驾驭工程 (Harness Engineering)”的第一性原理
- 用 Go 语言手写 ReAct 循环、并发拦截与上下文压缩引擎等,复刻极简OpenClaw
- 构建坚不可摧的 Safety Middleware 与飞书人工审批防线
- 在底层实现 Token 成本审计、链路追踪与自动化跑分评估
- 从“调包侠”进化为掌控大模型边界的“AI 操作系统架构师”
扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。

原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!
我们致力于打造一个高品质的 Go 语言深度学习 与 AI 应用探索 平台。在这里,你将获得:
- 体系化 Go 核心进阶内容: 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏,夯实你的 Go 内功。
- 前沿 Go+AI 实战赋能: 紧跟时代步伐,学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等,掌握 AI 时代新技能。
- 星主 Tony Bai 亲自答疑: 遇到难题?星主第一时间为你深度解析,扫清学习障碍。
- 高活跃 Gopher 交流圈: 与众多优秀 Gopher 分享心得、讨论技术,碰撞思想火花。
- 独家资源与内容首发: 技术文章、课程更新、精选资源,第一时间触达。
衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。
