make 构建磁盘写满 No space left on device 速查
更新时间:2026-10-24。FAQ 速查页,面向在开发机或 CI 上跑构建的同学。make 构建磁盘写满指编译进行到一半,gcc/as/ld 往磁盘写中间文件或最终产物时报
No space left on device,make 随即以 Error 中止。它和 make 编译内存超限速查 是一对镜像病——一个是内存不够,一个是磁盘不够,报错都出现在编译最吃资源的环节。磁盘写满的讨厌之处在于:报错点往往不在病根上,真正吃掉空间的可能是一周前攒下的 ccache 或日志。本篇以报错原文为锚逐条定位。
本文要回答的问题
No space left on device报在编译中途,到底是哪一步写爆了?- 明明
df -h看还有空间,为什么还是写不进去? - ccache 明明设了上限,为什么缓存目录还是几十 GB?
- CI 上每周定时挂一次构建,清完又能跑几天,怎么根治?
- 构建产物该往哪儿放,才能不跟系统分区互相拖累?
一、报错原文与典型现象
典型现场(工程路径以 /proj/demo 占位),编译到某个大文件时翻车:
$ make -j8
g++ -O2 -c src/render/engine.cpp -o build/engine.o
as: fatal error: can't write build/engine.o: No space left on device
make: *** [Makefile:42: build/engine.o] Error 1另两种高发长相:链接阶段写最终二进制时爆掉(collect2: fatal error: ld terminated with signal ... 或 ld: final link failed: No space left on device),以及预处理阶段往临时目录写 .s 文件就失败(cc1plus: fatal error: error writing to /tmp/ccXk2Qp.s: No space left on device)。还有一种最坑的变体:df -h 看分区还有 10 GB,构建照样报写满——这是 inode 耗尽,小文件太多把索引节点用光了,df -i 一看 IUse% 是 100。读懂现场抓住三件东西:哪个工具报的(as 写 .o、ld 写可执行文件、cc1plus 写临时文件,指向不同的目录)、写到哪个路径(工程 build/ 还是 /tmp)、是字节满还是 inode 满。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| as 写 .o 报 No space left | build/ 所在分区字节写满,模板重的 C++ 单 .o 可达数百 MB | df -h . 看当前分区 | 清旧产物 make clean;把 build/ 挪到大分区 |
| cc1plus 写 /tmp 临时文件失败 | /tmp 在小分区或 tmpfs 上,并行 8 个编译同时写临时文件 | df -h /tmp | 设 TMPDIR=/proj/demo/tmp 指到大分区 |
df -h 有余量但仍报写满 | inode 耗尽,海量小文件(头文件缓存、单测产物) | df -i 看 IUse% | 清小文件重灾区;格式化级调整不在本篇范围 |
| 清完没几天又满 | ccache 无上限增长、或设了上限但 CCACHE_DIR 指错目录实际没生效 | ccache -s 看 cache size 与 max size | ccache -M 5G 限上限、ccache -c 立即清理 |
| CI 机器每周定时挂 | 每次构建日志全量落盘 + 旧构建目录不轮替 | du -sh /proj/demo/logs/* 排序 | 日志 logrotate 或保留最近 N 份;旧 build 目录定期删 |
| Docker 构建越来越慢后失败 | 镜像层与 dangling 镜像堆积,/var/lib/docker 膨胀 | docker system df | docker system prune;构建加 --rm,分层合并 |
三、排查决策图
下面这张图按「字节满还是 inode 满、哪个目录满的」分岔:红是报错入口与命中的根因,蓝是排查动作,绿是验证通过,橙是修复动作,紫是防复发沉淀。
读这张图抓一条主线:先别急着删东西,用 df -h 和 df -i 两刀把「字节满 / inode 满」分开,再用 du -sh 从根往下逐层排序找到真正的吞盘大户——十次里有七次是 build 产物、ccache、日志这三样之一,删错目录(比如误删系统缓存)反而引入新病。
四、逐条排查展开
中间 .o 体积爆炸是 C++ 工程的常态。 开了 -g 加模板重的代码(boost、Eigen、大型头文件库),单个 .o 几百 MB 不稀奇;make -j8 时 8 个编译进程同时往 build/ 里写,一次全量构建峰值占用可能是最终产物的 5 到 10 倍。处置分两层:日常增量构建不需要留全量产物,make clean 或干脆删掉 build/ 重配;磁盘长期紧张的机器上把 build/ 放到独立的大分区,软链回工程目录,跟系统分区隔离。
/tmp 是个隐形瓶颈。 cc1plus 编译时先往 TMPDIR(默认 /tmp)写汇编临时文件,/tmp 在小分区或内存 tmpfs 上时,并行构建很容易把它打满。一行环境变量解决:export TMPDIR=/proj/demo/tmp,指到工程所在的大分区。
inode 耗尽最会伪装。 海量小文件场景——每个头文件预编译产物、每个单测的临时输出、npm/node_modules 式依赖——字节看着不多,inode 先用光。df -i 确认后,用 find /path -type f | wc -l 配合 du --inodes 找小文件重灾区,删掉或打包归档。
ccache 是双刃剑。 它能砍掉一半以上重复编译时间,但默认上限之外的场景(CCACHE_DIR 指错、多个工程共用一个 cache、老版本默认上限偏大)会一直长。ccache -s 看真实占用,ccache -M 5G 设上限,ccache -c 手动清。团队共享构建机建议把 ccache 目录也放独立分区。
日志与 CI 轮替。 每次构建 make 2>&1 | tee build.log 全量落盘,CI 一天几十次构建,日志目录几周就是几个 GB。配 logrotate 或脚本只保留最近 N 份;旧构建目录按编号轮替,别无限保留。
Docker 构建的特殊性。 每条 RUN 产生一层,层不会被后续层的 rm 真正释放;dangling 镜像和构建缓存堆在 /var/lib/docker。docker system df 看占用,docker system prune 清悬空资源;写 Dockerfile 时把「装依赖、编译、清理」合并在一条 RUN 里。
清理顺序有讲究,先问再删。 du -sh 排出来的大户里,build/ 与 logs/ 可以放心删,随时能重建;但 ccache 删完意味着下一次全量构建慢回原形,共享机器上先 ccache -c 只清旧条目、保留近期热缓存;系统目录(/var/cache、包管理器缓存)动了可能影响别的服务,不在构建排错范围内就别碰。拿不准的目录先 mv 成 .bak 观察一天,确认无异常再真删,比删错了恢复便宜得多。
五、规范做法与预防
- 构建目录与系统分区隔离:build/、ccache、TMPDIR 统一指到数据盘,系统分区只留操作系统和工具链。
- CI 前置水位检查:构建脚本开头加一行
df -h检查,使用率超 80% 先触发清理再开工,把故障挡在构建前。 - 给每类产物设上限:ccache 限大小、日志限份数、Docker 定期 prune,靠配额不靠人肉记性。
- 监控双指标:字节使用率和 inode 使用率都要告警,只盯
df -h会漏掉小文件风暴,等编译报出来已经是事故而不是预警。 - 清理命令进 Makefile:
make clean之外加make distclean(连配置产物一起清)和make cleanlogs,让清理动作一键可达。
这一篇在知识体系里的位置
本篇是 Makefile/CMake 排错速查簇的磁盘资源篇,管构建期写盘失败这一类病。资源类另一侧的内存问题看 make 编译内存超限速查;编译器自身崩溃见 make 编译器内部崩溃速查;写不了但报权限错误的分流到 构建 Permission denied 速查;配置与依赖类问题见 fatal error 头文件找不到速查、CMake 找不到依赖包速查、make: No rule to make target 速查;链接期报错见 undefined reference 链接错误速查 与 multiple definition 重复定义速查;构建行为怪异的看 CMakeCache 陈旧行为怪速查、并行构建偶发失败速查、make 构建卡死无响应速查;其余岔路见 CMakeLists 语法错误速查、Makefile missing separator 速查、CMake 版本不兼容速查、CMake 找不到编译器速查、CMake FetchContent 拉取失败速查、make 构建输出乱码速查、error: cannot convert 类型不匹配速查;同批的 优化构建 gdb 看不到变量速查 与 make 不知道编什么速查 分别管调试信息与默认目标两类入门坑。「df -h 配 df -i 双指标」这条排查法对一切写盘类报错通用。
一句话总结
make 构建磁盘写满先别急着删文件:df -h 看字节、df -i 看 inode 把病分两类,再 du -sh 逐层排序定位吞盘大户——十次有七次是 build 产物、ccache、日志三样;修复靠 make clean、ccache -M 限上限、日志轮替与 TMPDIR 挪大分区,长期靠 CI 前置水位巡检与配额制把磁盘故障挡在构建开始之前。