<p>go mod download 的临时文件实际不存在,下载的压缩包解压后缓存在 $GOCACHE/download/cache,模块快照存于 $GOCACHE/pkg/mod/cache/download 和 unpack,属长期缓存;真正瞬时临时文件是 go build 在 /tmp/go-build* 下创建的构建工作目录,构建结束即删。</p>

go mod download 之后的临时文件在哪
Go Modules 在下载依赖时,会把压缩包解压到 $GOCACHE 下的 download 子目录(如 $GOCACHE/download/cache),但真正参与编译的是解压后缓存在 $GOCACHE/pkg/mod/cache/download 和 $GOCACHE/pkg/mod/cache/unpack 中的模块快照。这些不是“临时文件”,而是长期缓存——除非你手动清理或缓存过期。
真正需要关注的临时文件,其实是 go build 过程中生成的中间对象:$GOCACHE/pkg/ 下按平台和哈希组织的 .a 文件(归档)、go tool compile 写入的临时符号表、以及 go tool link 阶段产生的链接中间体。它们默认不落地为可见文件,但会占用 $GOCACHE 空间。
-
go build -x输出里能看到类似/tmp/go-build123456789/b001/_pkg_.a的路径——这是每次构建时在系统/tmp创建的瞬时工作目录,构建结束即删 - 如果你用了
-toolexec或自定义 linker,工具可能额外落盘临时文件,需检查其行为 - 含
replace的本地路径依赖不会被缓存进$GOCACHE/pkg/mod,而是直接从源码编译,所以每次修改都会触发重新编译对应包(无中间缓存复用)
为什么 replace 本地依赖会导致反复编译
当你在 go.mod 里写 replace github.com/user/lib => ../lib,Go 工具链就不再查 $GOCACHE/pkg/mod,而是每次构建都重新读取 ../lib 目录下的源码、解析 AST、生成新哈希、编译成新 .a。这不是 bug,是设计使然:本地路径被视为“未版本化内容”,无法做内容寻址缓存。
- 即使你只改了
lib里一个空行,整个包及其下游所有依赖都会重编 -
go list -f '{{.Stale}}' ./...会显示被replace的包始终为true,说明它永远“过期” - 避免方式:调试完尽快切回
require+ tag 版本;或用go mod edit -replace临时加,配合脚本自动还原
如何安全清理与控制临时产物
不要直接删 /tmp/go-build* 或 $GOCACHE,而应交由 Go 工具链管理。真正影响构建速度的不是残留文件,而是缓存污染或路径冲突。
立即学习“go语言免费学习笔记(深入)”;
- 清理无效构建缓存:
go clean -cache(比手动删$GOCACHE更安全,会校验哈希一致性) - 清空模块下载缓存:
go clean -modcache(适用于换代理、私有模块路径变更后校验失败场景) - 禁用临时目录重用:设置
GOTMPDIR=/dev/shm(Linux)可让/tmp落在内存文件系统,加快创建/删除速度,但需注意容量限制 - CI 中避免
go clean -cache:应复用$GOCACHE卷,否则每次构建都退化为首次慢速
本地依赖频繁编译时的替代方案
如果必须长期用本地 replace(比如多 repo 协同开发),靠清理临时文件治标不治本。关键是绕过“每次都重编”的链路。
- 把本地依赖编译成静态库:
cd ../lib && go build -buildmode=archive -o lib.a ./...,然后在主项目用//go:linker或 cgo 方式链接(适用极少数性能敏感场景,增加维护成本) - 用
go install安装本地模块到$GOPATH/bin或$GOBIN,再通过replace指向已安装的二进制(不推荐,破坏模块语义) - 最务实做法:接受局部重编开销,但用
go build ./cmd/app精确指定目标,避免go build ./...扫描无关包 - 对高频调试场景,写个 shell 函数封装:
gobuild() { go build -o bin/app ./cmd/app && bin/app "$@"; },跳过go run的隐式编译
本地依赖带来的编译开销,本质是 Go 对“可重现构建”的妥协——它宁可多花几秒,也不愿缓存未经版本锚定的代码。这点在团队协作时是优点,但在单机快速迭代时就是瓶颈。别指望靠删临时文件提速,得从依赖粒度和构建范围入手。


















