ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux磁盘空间清理实战:从缓存到日志,彻底释放硬盘

Linux磁盘空间清理实战:从缓存到日志,彻底释放硬盘 1. 先搞清楚缓存和垃圾文件到底占了什么便宜1.1 缓存不是洪水猛兽系统比你更懂“快”刚接触 Linux 的朋友一听到自己硬盘里有几 GB 的缓存第一反应往往是“赶紧删掉”。这个心情我特别理解Windows 用久了养成的习惯嘛——C 盘一红就开清理工具。但到了 Linux 这边情况不太一样缓存这东西你真得先分清楚再动手。Linux 的缓存大致分两类一类是内核层面的 page cache也就是系统把读写过的文件内容留在内存里下次再访问就不用重新从磁盘搬了。另一类是应用层面的缓存比如包管理器下载的 .deb 安装包、浏览器缓存的网页资源、编译时留下的临时文件、Docker 镜像层等等。前者是内核自动管理的内存紧张时会自动释放你根本不用管也最好不要去管。后者才是我们平时说的“垃圾文件”——它们所在的位置明确、占用固定、删了不影响正在运行的服务只是下次再用到的时候需要重新下载或重新生成。所以做清理的第一步不是急着敲命令而是先问一个问题这波缓存清了之后重新生成的代价是什么比如 apt 的安装包缓存清了之后系统正常运行不需要它只有重新安装软件时才要再下载而像 Docker 镜像删了之后如果要重新跑同一个容器就得重新拉镜像。这两者的“代价”差了一个量级清楚了这一点你才不会犯“把镜像全删了结果生产环境起不来”这种低级错误。1.2 Linux 下常见的“垃圾文件重灾区”我把日常运维和桌面使用中最容易堆积垃圾的位置整理了一张表大家先对着看一眼心里有个谱位置通常内容增长原因清理风险/var/cache/apt/archives安装包 .deb每次 apt install 都会留一份极低删除只是省得重新下载/var/log/journal系统日志systemd 日志无限增长低建议用 vacuum 限容/tmp临时文件程序崩溃、异常退出低但别清正在运行任务的临时目录~/.cache用户级缓存Chromium、Python、pip 等中部分软件需要重建/var/lib/docker镜像、容器层、构建缓存频繁 build/拉取镜像高删错会导致镜像不可用~/.local/share/Trash回收站用户删除的文件极低/var/tmp跨重启保留的临时文件部分服务运行残留低最好按时间清理旧内核/boot 下的 vmlinuz 和 initrdapt upgrade 累积低但别删正在运行的版本这张表我建议收藏后面讲到具体命令时会一一对应。还有一点值得注意很多国产 Linux 发行版比如统信 UOS、麒麟和 Ubuntu/Debian 的目录结构基本一致所以下面这些操作方法在国产系统上一样适用只是个别包管理器命令要从 apt 换成他们自带的工具。1.3 清理前必须养成的两个好习惯在展示命令之前先讲两个惨痛教训换来的规矩。第一个教训叫“不要在生产环境上边操作边查命令”。我早年在一台数据库服务器上清理磁盘时想当然地执行了rm -rf /tmp/*结果那个 Web 应用正好把 session 文件放在 /tmp 的子目录里成品直接全部掉线排查了半天才发现是自己闯的祸。所以后来我定下一条死规矩任何清理操作先看目录内容再确认文件类型最后才动手。第二个教训叫“万物皆可先 dry-run”。这条在 Linux 上特别适用。很多清理工具、命令都提供了“只统计不执行”的模式比如journalctl --disk-usage只显示日志占用apt-get clean不需要 dry-run 但你可以先用du看好大小再决定清不清。任何拿不准的命令先查一下 manual或者用一个无关紧要的副本试一把比你事后后悔要稳妥得多。另外建议在动手之前先记录一下当前的磁盘占用情况比如df -h /看一眼根分区用了多少。清理完之后再跑一次你就能直观看到到底腾出了多少空间。这个习惯尤其适合写笔记、写分享也是做技术记录最基本的素养。2. 磁盘空间大排查用命令把每一块空间都翻出来2.1 df 和 du 的正确打开方式排查磁盘占用最核心的两个命令是df和du。听起来简单但很多人一直没搞明白两者的分工df是看文件系统整体使用率的du是看某个目录里文件累计大小。前者帮你回答“哪个分区满了”后者帮你回答“哪个目录塞满了”。先看df我一般固定这样用df -hT-h是人性化显示单位-T是显示文件系统类型。输出里你会看到 vfat、ext4、overlay、tmpfs 这些类型其中真正要关注的是挂载在 / 和 /home 上的 ext4 或 xfs 这类持久化文件系统tmpfs 是内存盘重启就没了不用操心。再看du排查时用这两个变体最多du -sh /var/log du -h --max-depth1 /var | sort -hr | head -20第一条是看单个目录的总大小第二条是列出一个目录下所有子目录的大小并按从大到小排序取前 20 个。我几乎每次排查都是从这条命令开始的直接把最大的那几块揪出来效率非常高。注意--max-depth1的意思是只看目标目录的下一级数字越大层级越深初查时用 1 就够了。2.2 被删文件不释放空间的本质还有一种特别让人崩溃的情况删了文件df 一看可用空间一点没涨。这时候就要讲 Linux 删除文件的底层机制了。在 Linux 中一个文件被删除实际是把它对应的目录项从父目录中移除同时减少它的链接计数。但如果这个文件正被某个进程打开着那么进程持有的文件描述符依然指向这个 inode文件的数据块不会被真正回收直到所有持有它的进程都关闭这个文件句柄为止。这也是很多服务器在线运行、日志被删了但空间不释放的原因。遇到这种情况用什么rm都没用因为问题不是“没删掉”而是“删的时候被占用了”。排查工具是lsoflsof L1这个命令专门用来列出所有“已被删除但仍被进程打开”的文件输出最后一列通常显示 (deleted)。看到之后找到对应的 PID重启这个进程空间立刻释放。如果你确定进程可以重启这是最干净的办法如果进程不能随便动那只能接受空间暂时不回收的事实等适当的维护窗口再处理。2.3 从“大头”开始定位三大排查路径排查磁盘空间除非你有明确的清理目标比如就是知道 Docker 占了十几个 G否则我都习惯按照固定的路径走一遍三下五除二就能定位到“大头”。第一站是日志目录。/var/log以及它下面的journal目录。用du -sh /var/log/*扫一遍如果超过 1GB 就要引起注意了尤其是老系统、长期不重启的生产机器这里常常藏了十几 GB 的历史日志。第二站是包管理器缓存。Debian/Ubuntu 系看/var/cache/apt/archivesCentOS/RHEL/Fedora 系看/var/cache/yum或/var/cache/dnf。执行 apt upgrade 频繁的机器这个目录涨得飞快几十 GB 不是没可能这些绝大多数是已经安装过、近期不会再用的安装包。第三站是用户家目录。尤其是~/.cache。很多图形应用、开发工具、浏览器都会往这里写缓存。有的目录名称特别不起眼比如~/.cache/thumbnails是缩略图缓存~/.cache/pip是 pip 下载的 wheel 包。这一站不一定会特别大但胜在“细水长流”天天在涨你天天看不到。把这三站都扫一遍之后磁盘空间的情况基本就心中有数了接下来再针对具体位置动手。3. 系统级缓存清理实操这些命令可以直接抄3.1 包管理器缓存apt 与 yum/dnf 的清理差异包管理器缓存是系统级缓存里最值得清理的一块因为它的占用最明确清理风险也最低。我用 Ubuntu 比较多先讲 apt 系列。sudo apt clean直接清空 /var/cache/apt/archives 下所有 .deb 文件。如果你只想清掉已经没用的旧版本保留最新版本可以用sudo apt autoclean sudo apt autoremoveautoremove虽然名字叫“自动移除”实际干的是卸载不再被依赖的旧包也算是一种垃圾回收。推荐顺序是先du -sh看看大不大再用autoclean温和清理最后用clean暴力清空。Red Hat 系这边命令稍微不一样sudo yum clean all # 或者新系统 sudo dnf clean all还有一个容易忽略的用 Snaps 的机器旧版本的 snap 包也会持续占用空间。Ubuntu 上检查一下snap list --all如果看到大量的 disabled 版本的包可以用脚本清理。官方没有提供一条简单的命令但这种场景网上有很多现成脚本核心逻辑就是遍历 disabled 的 snap 然后逐个卸载。3.2 journald 日志瘦身别再让日志无限膨胀了日志这个点90%的人不知道它的默认配置有多离谱。systemd 的 journald 日志默认情况下只受磁盘大小和文件数量的双 限制但默认值往往很大。查一下当前情况journalctl --disk-usage du -sh /var/log/journal两个命令得出的大小基本一致。如果你发现日志占了几个 G马上做两件事。第一件压缩现有日志到合理体积sudo journalctl --vacuum-size100M这会把日志总量压到 100MB 以内。这里的 100M 可以按你磁盘的实际情况调不敏感的业务日志 50M~200M 足够看重审计的需求请保留大一些。第二件修改配置让它以后不再膨胀。编辑 /etc/systemd/journald.conf SystemMaxUse200M MaxRetentionSec30dSystemMaxUse是日志最大占用MaxRetentionSec是最长保留时间两个都设置后journald 会自动滚动删除旧的日志。改完重启服务sudo systemctl restart systemd-journald这里有个小坑journald 重启后你原来 log 目录里的旧文件不会立即消失但新写入的日志会遵守新配置配合vacuum一起用效果最好。我自己的经验是先 vacuum再改配置顺序不要反。3.3 /tmp、/var/tmp 与孤儿文件的处理/tmp 这个目录是很多人的盲区。系统对它有自动清理机制但清理频率和策略因发行版而异有的系统默认只在开机时清理长时间不重启的机器的 /tmp 里就攒了大量垃圾。清理之前一定要确认没有运行中的任务正在使用它。判断方法很简单lsof | grep /tmp如果有输出说明有进程正在写 /tmp 下的文件这时候就别rm -rf /tmp/*了等任务结束再清。如果没有可以直接清sudo find /tmp -type f -mtime 7 -delete sudo find /tmp -type d -empty -delete不过我一直坚持用 find 按时间清理而不是盲目全删因为总有些软件会把 socket 文件、锁文件放到 /tmp 下面全部清掉会导致正在运行的服务出问题。同理 /var/tmp 也可以用相同逻辑只是它的生命周期比 /tmp 长建议按 30 天来清。3.4 旧内核隐藏的“空间刺客”Linux 系统更新内核之后旧内核不会自动删除而是保留在 /boot 下让你能在新内核有问题时回退。这个设计本身没问题问题是版本升级几十次之后/boot 分区会被塞满很多老机器上 /boot 分区只有 500MB~1GB几个内核就占满了。先确认当前内核版本uname -r再列出已安装的内核dpkg --list | grep linux-imageDebian/Ubuntu 系直接一条命令清理旧内核sudo apt autoremove --purgeautoremove会识别出所有不再需要的旧内核镜像并移除。CentOS 上手动删比较麻烦推荐用package-cleanupsudo package-cleanup --oldkernels --count2保留最近的两个版本这个数字可以根据需要调整。清理内核之前建议看一下当前用的内核是哪个千万别把正在运行的那个也删了。4. 用户级与容器缓存容易被忽略的隐藏大户4.1 常见工具缓存位置速查表系统级的清理做完后用户目录下的缓存才是很多人真正的痛点。如果你经常用开发工具你可能会惊讶地发现系统分区才用了 20GB但~/.cache一个人就占了 10GB。这是我整理的一份常用工具缓存位置表大家可以对照自查目录对应工具注意事项~/.cache/pippip 下载的安装包直接删没风险~/.cache/huggingface模型权重缓存删后需重新下载~/.cache/mozilla/firefox浏览器缓存删后首次打开稍慢~/.npmnpm 包缓存删除后可正常安装~/.nuget/packages.NET 包缓存体积大删后重建~/.m2/repositoryMaven 依赖删除后构建重新下载~/.cache/thumbnails文件管理器缩略图可不定期清~/.local/share/DockerDocker Desktop 数据别直接动手~/go pkg/modGo module 缓存删后重新下载~/.rustup/toolchainsRust 工具链删了得重装别乱清表格里这些目录我建议看到哪个超大就处理哪个。但有个原则必须告诉大家凡是带“cache”“缓存”字样的目录删了之后顶多就是重建、重新下载不会丢数据但像~/.m2/repository这种虽然也是“缓存”它里面其实混着你本地手动 install 的自定义 jar 包清之前要确认不是自己放进去的私包。4.2 Docker 缓存清理一步到位还是半自动Docker 是容器时代的大户它的磁盘占用分几块镜像层、运行中的容器可写层、数据卷、build 缓存。清理思路也不一样。最暴力也最常用的一条docker system prune -a -f这条命令会自动清理所有未被使用镜像、停止的容器、无用的网络和构建缓存。注意这里的-a会把所有没有被容器引用的镜像全删掉不只是 dangling 的所以如果你只是临时停了个容器想留着镜像下次再用别加-a。docker system prune -f更精准一点只删没有标签的镜像和已经停止的容器保留有名字有 tag 的镜像。这是日常维护的推荐姿势。但如果只是构建缓存爆炸比如你频繁用 Dockerfile 构建镜像build cache 很容易膨胀到几十 GB可以单清这一块docker builder prune -f很多人把 Docker 的存储位置改到数据盘了但那是另说。4.3 小心“缓存全清”的副作用三种“看起来像缓存的东西”清理缓存最危险的不是忘了清而是把不该清的东西当成缓存清了。这里讲三种典型的坑。第一种是“伪缓存”。比如 StarRocks、ClickHouse、Redis 这类数据库会把自己的一部分数据文件放在类似 cache 的目录里做中间存储你要是手贱把整个目录删了丢的可是真实数据。所以看见“cache”字样的目录先ls看清楚里面是什么格式的文件再决定动不动。第二种是“加密缓存”。比如 GNOME 的 keyring、SSH 的 known_hosts这些虽然也带一点缓存性质删了会导致你很多服务的认证全部失效要重新输入密码、重新确认主机指纹。这类文件通常不在 ~/.cache 目录下而是分布在 ~/.local/share 或 ~/.config 里但总有人“一不小心”全局扫描删到它们。第三种是“编译中间文件”。你用 ccache 之后编译缓存放在 ~/.cache/ccache这个删了只是下次编译变慢但有些同学会把 build 目录当缓存删掉如果你的项目是增量构建的删了 build 目录等于全量重新编译一次时间成本极高。所以我的个人字典里有一条铁律清理缓存之前先看三样东西——目录名、文件类型、有没有对应的运行任务。三个都确认过没问题再动手。5. 疑难杂症排查实录空间去哪了5.1 WSL 删除文件后 vhdx 不释放最经典的“空间失踪案”Windows 上跑 WSL 的同学几乎都踩过同一个坑在 WSL 里删了几 GB 文件Windows 侧的 vhdx 磁盘映像文件大小纹丝不动C 盘还是那么满。这个问题我曾经的排查结论是WSL 的 vhdx 是稀疏文件模式动态扩展删了文件之后如果不手动压缩虚拟磁盘文件不会自动收缩。解决办法有两个层级。第一个层级在 WSL 内部先做清理比如sudo apt autoremove、docker system prune然后退出 WSL打开 PowerShell执行wsl --shutdown再去 WSL 的安装目录找到对应发行版的 vhdx 文件用 diskpart 压缩。不过这种做法对新手太繁琐也有图形化工具直接做这件事比如 wsl2-diskutil 之类的开源项目原理是一模一样的。第二个层级更省心如果你想要一个“微信文件传输助手”式的清理体验在 WSL 内跑df -h看好了空间已经释放但 Windows 侧没缩那就接受它短时间不会缩的事实等 WSL 下一次自动收缩或者你手动 wsl --shutdown 之后再观察。说实话vhd 不自动回收这个机制微软官方做了这么多年也没做到像 ext4 那么透明知道了原因之后就不用怕了。5.2 lsof 查找占用已删除文件文件系统“隐形的内存黑洞”前面讲 df 和 du 的时候提到过文件被删但空间不释放是因为进程还占着文件描述符。这里我再给一个完整的排查实操。假设你清理了 /var/log/nginx/access.log但 df 一看根分区可用空间没有增加。按这个流程来lsof L1 | grep deleted输出里会看到类似这样的行nginx 1234 root 6u REG 8,1 10485760 3276800 /var/log/nginx/access.log (deleted)这里的 1234 是进程 PID/var/log/nginx/access.log就是那个已经被删除但还被占用的文件。处理动作取决于这个进程能不能重启如果能systemctl restart nginx如果不能就记录下这个文件句柄等下次维护窗口重启相应的服务。还有一种更隐蔽的情况Python、Node 这类解释型程序如果你用它打开了一个日志文件然后程序 fork 出了子进程子进程还握有这个文件句柄你光杀掉父进程是没用的必须把所有相关子进程找出来一起杀掉。lsof L1会列出所有持有者照着 PID 逐个处理。5.3 文件被进程锁住rm 删了也不减空间的最全排查思路如果lsof L1没找到任何 deleted 文件但空间还是没释放那问题可能不在文件被占用而在于你根本没有找到真正占空间的目录。这种时候我的策略是按挂载点来定位。先看根分区到底挂载在哪里mount | grep / 假设输出是/dev/sda2 on / type ext4那么真正占满它的是所有挂在它下面的文件但不包含挂载在其他分区的子目录比如 /home 可能是独立的 /dev/sda3。如果你只执行du -sh / *会被那些挂载了其他分区的目录干扰判断。正确的做法是排除掉这些挂载点du -h -x --max-depth1 / | sort -hr | head -20-x参数的意思是“只看与根分区同一个文件系统”的目录挂载在别处的目录直接跳过。这个命令是定位根分区“元凶”的最强武器。还有一种冷门但对某些用户很常见的场景zram 和 tmpfs 的占用。如果你使用了 zram 做交换分区或者把某些数据放在 /dev/shm 这类 tmpfs 里内存占用看起来像磁盘占用实际上删了文件后内存释放、df 也同样会变。这种情况不要用磁盘清理的思路去处理而是考虑调整 swap 配置和 tmpfs 大小。6. 自动化与工具一劳永逸的维护方案6.1 三条命令的“补救式清理”如果你想用最短的时间做一次“补救式清理”不需要深入每个目录这三条命令基本就够了sudo apt autoremove --purge sudo journalctl --vacuum-size100M sudo apt clean第一条删旧包第二条压日志第三条清安装包缓存。三步走完少则释放 500MB多则几个 G视系统使用时间而定。这三条命令全都有官方文档支持、行为可预期不会误删重要数据哪怕你是第一次用 Linux照着敲都不用太担心。如果是 CentOS/RHEL 系把第一条改成sudo dnf autoremove第三条改成sudo dnf clean all即可。这条配置组合我经常放到新装的开发机里“开箱即清”。6.2 systemd timer 定时清理后台管理员的正确姿态命令行清理适合“想起来才做”但真正干净的机器是靠“定时做”维持的。Linux 上实现定时任务最简单的是 crontab但我要推荐的是 systemd timer——它和系统日志、unit 状态检查这些天然集成没那么多坑。新建一个 service 文件 /etc/systemd/system/clean-journal.service [Unit] DescriptionClean journal logs Aftersystemd-journald.service [Service] Typeoneshot ExecStart/usr/bin/journalctl --vacuum-size50M ExecStart/usr/bin/apt-get clean再建 timer 文件 /etc/systemd/system/clean-journal.timer [Unit] DescriptionRun clean-journal weekly [Timer] OnCalendarweekly Persistenttrue [Install] WantedBytimers.target启用它sudo systemctl daemon-reload sudo systemctl enable --now clean-journal.timer这样每个星期系统会自动把 journal 压缩到 50MB、清一遍 apt 缓存。注意到没有我刻意不用rm或find -delete因为定时任务里要尽可能使用发行版自带的、语义明确的命令避免变量过多。6.3 图形/半图形工具与我的推荐组合如果你不习惯纯命令行或者管理的机器数量比较多可以借助一些工具完成批量清理。BleachBit 是我用得比较多的一个它在 Linux 上相当于 Windows 下的 CCleaner支持按应用分类清理浏览器缓存、临时文件、日志还有命令行模式bleachbit --clean可以集成到脚本里而且它默认就带了安全的白名单策略不会让你一键把重要文件清掉。但注意BleachBit 虽然方便我依然不推荐它成为你唯一的武器。原因很简单它没法分辨“这个 Docker 镜像还要不要用” “这个 Maven 缓存是自研私包还是公开依赖”这类业务上下文而这些恰恰是命令行清理时你自己能做判断的。所以在我的维护习惯里工具负责“系统级”的千篇一律命令行负责“业务级”的千差万别。最后分享一个我个人的小经验清理完一套流程之后顺手在终端里执行一次history | grep 清理把用过的命令整理成自己的备忘录。不同发行版、不同业务上下文的清理套路是有差异的但只要你记录下每次的“核心步骤 释放空间大小 清后是否有问题”就能逐步沉淀出一套真正适合你自己的维护手册。这个习惯坚持两年以上你对一台机器的掌控力和只会背命令的人完全是两个层次。
返回列表