Linux垃圾文件清理与磁盘空间释放实战指南
2026/9/13 8:56:29 网站建设 项目流程

1. 先搞清楚:这些“垃圾文件”是怎么在Linux里攒起来的

很多刚接触Linux的朋友都有过类似的困惑:明明没装几个软件,磁盘空间却一天比一天少。打开文件管理器一看,也不知道去哪找那些占空间的东西。更麻烦的是,和Windows不一样,Linux没有C盘D盘的概念,垃圾文件散落在系统各处,想删又怕删错导致系统出问题。

我最早用Linux的时候也踩过这个坑。当时以为清理垃圾就是把/tmp里的东西全删了,结果删到一半系统卡死,重启之后X服务起不来,折腾了一下午才弄明白是删掉了某个运行中的进程还在用的socket文件。从那以后我养成了一个习惯:动手清理之前,先搞清楚Linux的“垃圾”到底散落在哪些地方,以及哪些能删、哪些不能删。

先看一个最关键的问题:Linux的缓存到底算不算垃圾?

很多人一进系统就爱运行free -h,看到buff/cache那一栏占了好几个G就心慌,觉得是缓存吃掉了内存,急着想清掉。实际上这是Linux的正常工作方式——内核把空闲的内存用来缓存磁盘数据,目的是加速文件读写。这块缓存完全可以超卖,也就是说当有程序真正需要内存时,内核会自动回收这部分缓存,不会造成内存不足。你手动去清/proc/sys/vm/drop_caches,短期内看着内存数字变好看了,但之后的磁盘IO性能会明显下降,属于典型的“自我安慰式清理”。

所以我说,缓存这个概念要先拆分来看:内核层级的缓存(page cache、dentry cache、inode cache)不算垃圾,不用管,也没必要管;真正需要我们关心的,是软件应用在工作过程中产生的那些不会再被用到的临时文件、日志片段、下载缓存、构建中间产物,这些才是“无用缓存及垃圾文件”的真正定义。

从这个角度出发,我把日常维护中常见的“垃圾来源”列了一张表,大家可以对照自己的系统排查:

类型典型位置占空间程度
包管理器缓存/var/cache/apt/archives/var/cache/dnf/var/cache/pacman/pkg高,重装系统后尤其明显
系统日志/var/log/journal/var/log/*.log高,默认配置下可能占几个G
用户临时缓存~/.cache~/.local/share/Trash中,随使用时间持续累积
应用软件缓存~/.config下的各类子目录、浏览器缓存、微信/QQ数据目录高且隐藏较深
开发工具缓存~/go/pkg/mod~/.gradle/caches~/node_modules/.cache~/.npm极高,部分目录可占几十G
编译中间产物/usr/src/var/tmp、各类build目录视项目而定,可能很大
容器相关Docker的build cache、停止的容器镜像层、无用的volume极高,容易一查吓一跳

看完这张表你就明白了:Linux的“垃圾文件”问题,本质上是缓存散落各处却缺少统一的回收机制。Windows系统里有个磁盘清理工具能统一扫描临时文件,Linux这边就没有这种开箱即用的统一入口,得靠我们自己手动或写脚本来处理。下面我按实操顺序,把清理的重点逐项拆开讲。

2. 包管理器与日志文件:最值得清理的两块“显性垃圾”

如果说系统里有一个地方是垃圾文件的“重灾区”,那一定非包管理器缓存莫属。不管你是哪一派系的发行版用户,这一点都逃不掉。我见过很多Ubuntu用户,装完系统用了大半年,/var/cache/apt/archives里躺着五六个G的deb安装包——这些安装包在软件装完之后就完全没用了,但系统默认不会自动删除它们。

2.1 apt/dnf/pacman系:三种包管理器的清理姿势

我用过的发行版比较多,从早期玩CentOS、后来转到Debian系、再到现在主力用Arch系和Ubuntu Server,每种包管理器的缓存清理命令都背得滚瓜烂熟。这里直接给出一张对照表:

包管理器所属发行版清除缓存命令额外清理
aptDebian/Ubuntu系sudo apt-get cleansudo apt-get autoremove
aptDebian/Ubuntu系sudo apt-get autoclean只清理过期的安装包
dnfFedora/RHEL系sudo dnf clean allsudo dnf autoremove
pacmanArch系sudo pacman -Sccsudo pacman -Sc(保留最新版本)

这里有个多数人容易混淆的点:apt-get cleanapt-get autoclean到底有什么区别?简单来说,clean是把缓存目录里所有已下载的deb安装包全部删掉,一个不留;而autoclean只删除那些已经无法再从软件源下载到的“过期”包,还能下载的包保留着。从清理效果来看,clean更彻底,但如果你的网络环境不太稳定,我建议用autoclean,保留一份最近安装过的安装包,万一软件出问题了还能本地重装。

还有一个命令经常被忽略:apt-get autoremove。这条命令的作用是把“为了满足依赖而自动安装、但现在不再被任何软件依赖”的包自动移除。系统更新迭代过程中会产生很多这种孤儿依赖,我见过一台跑了一年多Nginx+MySQL的Ubuntu服务器,autoremove一次性清出了2个多G的空间。DNF系也有同名的autoremove命令,Arch系则需要在pacman -Qtdq(查无用的依赖包)后配合pacman -Rns手动处理。

2.2 journal日志:Linux日志系统的清理边界

日志文件是另一个隐藏很深的“空间杀手”。新版systemd系列的发行版,所有系统日志都由journald统一管理,默认存放在/var/log/journal目录下。很多人在安装系统后不去调整journald的配置,于是这个目录会随着系统运行时间持续膨胀。我见过一台跑了三个月的个人服务器,光journal目录就占了快4G,全是内核消息和系统服务的日志片段。

清理journal日志不需要像老式做法那样删文件——直接删journal文件可能导致日志服务异常。正确方式是让journald自己压缩旧的日志,这里提供两种常用姿势:

# 只保留最近7天日志,其余全部清理 sudo journalctl --vacuum-time=7d # 或者指定日志总大小上限,超过自动清理最老的 sudo journalctl --vacuum-size=100M

在确认journallog清理没问题的同时,我建议你直接修改配置来控制未来的增长,这样以后不用再频繁手动清理:

# 编辑journald配置文件 sudo vim /etc/systemd/journald.conf

找到SystemMaxUse这一行,取消注释并设置上限,例如:

SystemMaxUse=200M

设置完重启日志服务:

sudo systemctl restart systemd-journald

把日志总大小锁死在200M以内,journald会自动轮转和清理旧日志,再也不用担心日志撑爆磁盘。这个技巧对服务器运维场景尤其重要——很多线上事故都是日志把磁盘写满导致的。

需要特别提醒:journal日志和/var/log下的经典文本日志(如syslogauth.logkern.log)并不是一码事。如果你用的是传统rsyslog方案,清理姿势是truncate或删除旧日志文件,可以参考下面的方式:

# 清空当前syslog文件,而不是删除(删除可能导致服务句柄异常) sudo truncate -s 0 /var/log/syslog sudo truncate -s 0 /var/log/auth.log

3. 用户家目录与开发环境缓存:容易被忽略的“隐形仓库”

刚才讲的包管理器和日志,是最容易发现的两块“显性垃圾”。但如果你在个人电脑或开发机上做清理,真正让磁盘空间悄悄消失的大头,其实躺在用户家目录和开发环境里。很多人的根分区没大多少,但家目录挂载的分区却经常报警,排查下来基本都是这类“隐形缓存”惹的祸。

3.1 先学会给家目录做“体检”

动手清理前,第一步永远是弄清楚空间到底被谁占用了。我用两个命令组合来完成这个事情:

# 列出家目录下各个子目录的大小,从大到小排列 du -sh ~/* 2>/dev/null | sort -rh | head -20

这条命令的意思是把~下的每个子目录大小统计出来,按从大到小排序,只显示前20个。执行之后你会瞬间明白家里的“空间大户”是谁。我第一次跑这个命令是在一台我用了两年的Ubuntu笔记本上,结果显示~/.cache占用了8个G,我当时都惊了——从来不知道这个目录会攒这么大。

如果要单独看某个具体目录,可以再用:

# 看看~/.cache里到底是什么占了空间 du -sh ~/.cache/* 2>/dev/null | sort -rh | head -20

3.2 ~/.cache与用户级临时文件的安全清理

确认了占空间大户之后,下一步是搞清楚哪些能删。

~/.cache这个目录理论上就是给应用程序存临时缓存的地方,清掉之后系统不会坏,最多是下次打开软件时重新生成缓存。但这里有个坑:有一些软件的缓存里保存了未保存的对话记录、草稿之类的数据,比如某些编辑器、浏览器扩展。所以稳妥的做法是优先清理那些确定可以重新生成的缓存子目录,比如:

  • ~/.cache/thumbnails:系统缩略图缓存,删了会重新生成,放心删
  • ~/.cache/pip:pip下载的安装包缓存,删了不影响已装包
  • ~/.cache/mozilla/firefox/.../cache2:火狐浏览器的缓存文件,清理无风险
  • ~/.cache/google-chrome/.../Cache:Chrome缓存,同理

对于不确定的子目录,我建议用ls -lt看修改时间,如果修改时间是一年以前、甚至更早,那基本可以确认属于“死缓存”,可以直接清理。

另外和大家推荐一个我一直在用的笨办法——用find找出N天没访问过的文件批量处理:

# 找出~/.cache下30天以上没有被访问的文件,列出来看看 find ~/.cache -type f -atime +30 2>/dev/null | head -50 # 确认没问题后,把这些文件删掉 find ~/.cache -type f -atime +30 -delete 2>/dev/null

用atime(访问时间)是因为缓存的价值在于“被使用”,一个30天都没被读取过的缓存文件,将来被用到的概率微乎其微,删掉合情合理。

3.3 开发环境缓存:最容易让人肉疼的清理项

如果你用Linux做开发,那家目录里的开发工具缓存绝对是“空间吞噬者”的T0级别。我用Go和Python比较多,又跑过一阵子Node和Java项目,对这几个生态的缓存规模深有体会:

开发工具缓存目录清理命令/方法
pip~/.cache/pippip cache purge(新版pip支持)
npm~/.npm/_cacachenpm cache clean --force
yarn~/.cache/yarnrm -rfyarn cache clean
Go module~/go/pkg/mod/cachego clean -modcache(说明:此命令用于清理模块缓存)
Gradle~/.gradle/cachesrm -rf ~/.gradle/caches,或使用gradle cleanBuildCache
Maven~/.m2/repository谨慎,这是本地依赖仓库,重装依赖才会重新下载
Docker/var/lib/dockerdocker system prune -a(清理所有无用的镜像、容器、网络、build cache)

这条表里最让人纠结的是Maven的~/.m2/repository,因为这里存的不只是缓存,还有你自己安装到本地仓库的构件。如果直接清空,后续构建项目时全部重新下载依赖不说,某些公司内部私有构件可能会直接丢了找不回来。我的建议是:Maven仓库只清理~/.m2/repository下的.lastUpdated后缀文件和_remote.repositories标记文件,这些属于下载失败的残留,清理无风险:

# 清除Maven下载失败的残留 find ~/.m2/repository -name "*.lastUpdated" -delete

Docker的build cache这几年也膨胀得厉害。如果你常用Docker构建镜像,一个docker system df查看结果可能会让你瞪大眼睛——build cache动不动就是十几个G。这些缓存本质上是为了加速镜像构建的层缓存,但时间一久、Dockerfile改来改去之后,大量旧层缓存就变成了仅供存疑的“死空间”。定期执行docker builder prune -f能释放很大一部分空间,更彻底的docker system prune -a则会连没在用的镜像和容器一起清掉。

4. 清理后空间没有释放:必查的几个方向

自己动手清理完上面那些地方,大部分情况下磁盘空间都能恢复正常。但如果你遇到的是我之前踩过的另一个坑——明明把几G的文件删了,df -h一看,可用空间一丁点没涨,那可别急着给系统判死刑。这个现象背后的原因有几类,其中两个最典型,我专门写一节来分享排查思路。

4.1 被进程占用的已删除文件

这个原因我当年排查了很久才想明白。在Linux里,如果一个进程打开了某个文件,你把文件从磁盘上删除(unlink),文件系统层面确实看不到这个文件了,但进程的文件描述符依然指向那个文件的inode,占用的磁盘块不会被释放,直到进程关闭这个文件句柄或进程退出。

举个例子:你在跑一个持续写日志的程序,比如Nginx,它的access.log一直在增长。你用rm /var/log/nginx/access.log把它删了,但Nginx进程还开着这个文件,于是磁盘空间只会“假释放”——从目录结构看文件没了,实际占用的block还钉在磁盘上。

遇到这种情况,参考下面的排查步骤:

# 找到被删除但仍被进程占用的文件 lsof +L1

+L1的意思就是列出link count为0但依然被打开的文件。看到输出后,对照PID找到对应的进程,确认这个文件确实没用了,那就重启这个进程让文件真正释放。如果是日志类文件,更稳妥的做法是用truncate而不是删除,这样既不中断进程,也能释放空间:

# 把日志截断为0字节,不清除文件本身 sudo truncate -s 0 /var/log/nginx/access.log

这个方法适合容器场景和常驻服务写日志的场景,基本上遇到“删了空间没释放”的问题,十有八九就是这类情况。

4.2 文件系统元数据与快照导致的“既视感”

还有一种情况是删完文件后df -h显示使用率没变,但过一会又降下来了。这个往往是文件系统(尤其是btrfs、zfs这类写时复制文件系统)在后台做元数据更新和块回收引起的,因为它们的空间统计和释放动作不是实时的,有一定延迟。如果你用的是btrfs且开了快照功能,那更需要注意:旧快照里可能含着你刚删掉的文件数据,那些空间被快照“锁定”了,自然释放不了。

检查方式:

# 查看btrfs子卷和快照 sudo btrfs subvolume list / # 查看快照占用 sudo btrfs filesystem du --summarize /

如果确认快照过多,删除不再需要的旧快照即可。一般情况下,我建议保留最近一两份快照作为回滚保底,其他就按需清理。

类似的情况也出现在Docker的overlay2存储驱动里。有时候你在容器里删了一堆文件,但镜像层里的数据还在,因为Docker的镜像层是只读的,只有通过创建新镜像覆盖或docker image prune才能释放。所以“容器里删了文件,宿主机空间没涨”也不奇怪,这属于Docker的分层存储特性。

5. 清出空间后的自动化运维:脚本与定时任务的取舍

手动清理一次容易,难的是维持。Linux系统用久了,垃圾文件的产生速度永远比你手动清理的速度快。尤其像我这种家里有服务器长期开机、同时又跑着几个Docker容器的人,几天不管,空间又悄悄涨回去了。所以我在经历了几次“磁盘报警→手动清理→过段时间又报警”的循环之后,干脆写了一套自动清理脚本,配合systemd的timer做定期执行,效果非常稳定。这里我把思路和踩过的坑一并分享出来。

5.1 设计一个“安全优先”的清理脚本

自动清理脚本最怕两件事:一是误删了系统还需要的东西,二是清理逻辑太激进导致服务异常。所以我的脚本设计原则只有一条:优先只清理确定安全的垃圾,宁可不清理,也不乱清理

参考下面这个脚本:

#!/bin/bash # 安全清理Linux垃圾文件,支持--dry-run参数查看将要清理的内容 set -euo pipefail LOG=/var/log/clean-system.log DRY=false # 解析参数 [[ "${1:-}" = "--dry-run" ]] && DRY=true log() { echo "$(date '+%F %T') $*" >> "$LOG" } clean_pkg_cache() { # 各发行版包管理器缓存 if command -v apt-get >/dev/null; then $DRY && { echo "[DRY] apt-get autoclean"; return; } apt-get autoclean -y >> /dev/null 2>&1 apt-get autoremove -y >> /dev/null 2>&1 log "apt cache cleaned" elif command -v dnf >/dev/null; then $DRY && { echo "[DRY] dnf clean all"; return; } dnf clean all >> /dev/null 2>&1 log "dnf cache cleaned" elif command -v pacman >/dev/null; then $DRY && { echo "[DRY] pacman -Sc"; return; } # 保留最新版本缓存,删除过时包缓存 pacman -Sc --noconfirm >> /dev/null 2>&1 log "pacman cache cleaned" fi } clean_journal() { $DRY && { echo "[DRY] journalctl --vacuum-size=100M"; return; } journalctl --vacuum-size=100M >> /dev/null 2>&1 log "journal trimmed to 100M" } clean_user_cache() { # 清理当前用户常见缓存目录下超过30天未访问的缓存文件 if [[ -d "$HOME/.cache" ]]; then if $DRY; then find "$HOME/.cache" -type f -atime +30 2>/dev/null | head -20 else find "$HOME/.cache" -type f -atime +30 -delete 2>/dev/null log "user cache cleaned" fi fi } clean_tmp() { # 清理/tmp下符合条件的临时文件(排除运行中程序的socket等特殊文件) $DRY && { echo "[DRY] /tmp check"; return; } find /tmp -type f -atime +2 -delete 2>/dev/null || true log "tmp cleaned" } clean_docker() { if command -v docker >/dev/null; then $DRY && { echo "[DRY] docker system prune -f"; return; } docker system prune -f --filter "until=72h" >> /dev/null 2>&1 log "docker pruned" fi } # 主流程 echo "开始执行清理任务 (DRY: $DRY)..." clean_pkg_cache clean_journal clean_user_cache clean_tmp clean_docker echo "清理任务结束,详细日志见 $LOG"

脚本里我特意加了--dry-run参数,可以用来在执行前预览将要清理的项目。这个习惯帮我避免过几次误删——记得有一次--dry-run输出里包含了某个服务正在使用的旧socket文件,幸好先跑了一遍查看,才没有把运行中服务的通信文件清掉。

5.2 用systemd timer定时执行,而不是crontab

很多人习惯用crontab做定时任务,但如果你用的是新版systemd体系的发行版,我更推荐systemd timer方案。它的好处有三个:一是能配置持久化(mISSed任务补跑);二是能查看最近运行状态;三是和系统的unit状态管理集成,查日志方便。

先创建一个service文件:

# /etc/systemd/system/clean-system.service [Unit] Description=Clean system junk files After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/clean-system.sh

再创建一个timer文件:

# /etc/systemd/system/clean-system.timer [Unit] Description=Run clean-system weekly [Timer] OnCalendar=weekly Persistent=true [Install] WantedBy=timers.target

然后启用并启动timer:

sudo systemctl daemon-reload sudo systemctl enable --now clean-system.timer sudo systemctl start clean-system.timer

之后每周系统就会自动运行一次清理脚本。想看上次执行时间和结果,用systemctl status clean-system.timerjournalctl -u clean-system.service即可。这套组合我跑了快两年,没出过任何岔子。

需要特别提醒:对于生产环境的数据库或核心服务主机,我建议不要直接启用上面这套自动清理逻辑。数据库目录、消息队列的临时消息文件都不属于普通缓存,自动脚本一旦误判后果会很严重。生产环境强烈建议只清理journal日志和包管理器缓存,其他项目都手动确认后再执行——这是我做过的最保守也最稳妥的选择。

6. 特别提醒:哪些“垃圾”看起来能清、实际不能乱动

写到最后,我还想单独整理出一类“清理陷阱”。很多人看网上教程,知道了一些清理命令后就见什么删什么,结果往往清出问题。下面这几个场景是实际运维和日常使用中最容易踩坑的地方,全部是我自己或周围朋友经历过、翻过车的,特别提示给各位。

/tmp/var/tmp不能一刀切:系统确实会定期清理/tmp,但/var/tmp默认保留的时间更长(通常是30天),有些应用会把临时状态文件放在/var/tmp,比如编辑器恢复文件、数据库的临时排序文件等。你如果直接把所有文件都删了,可能导致正在运行的服务中断。安全做法是只清理修改时间超过两天的文件,而且先用-delete之前加-print查看一遍列表。

内核源码目录和编译产物别乱清理:比如/usr/src下的内核头文件、dkms模块源码,这些看起来像是没用的旧代码,但有些内核模块在升级时还需要它们。如果你不是极度缺空间,/usr/src里的东西建议保留,而不是看见目录大就动手。

snap的旧版本缓存:Ubuntu用户如果发现df -h显示snap loop设备占空间,那多半是snap包装应用的历史版本文件。清理方式是sudo snap set system refresh.retain=2,然后执行sudo snap refresh让系统移除旧版本,不要直接删除/var/lib/snapd下的文件,否则snap服务会直接报错。

浏览器配置文件不要直接删:浏览器会把密码、书签、扩展设置都存在~/.config~/.mozilla目录下,这部分不属于缓存,删了等于重置浏览器。真正能清的是各个浏览器自己的Cache子目录。

home目录下的“隐藏文件夹”先看清楚再动手:很多人看到~/.local~/.config占了大量空间,想直接rm -rf,这属于重破坏行为。~/.local/share里往往有应用的数据文件(比如一些游戏的存档、邮件客户端的本地邮件存储),删了不可恢复。

个人经验收尾

做Linux系统维护这十多年,我最深的体会之一是:清理垃圾文件这件事,本质上是在给系统“做减法”,而这个减法最难的地方不在于“删”,而在于“判断”。判断哪些是垃圾、哪些是数据,判断哪些能自动清理、哪些必须留给人来决策,这比记住几条命令重要得多。

我现在的习惯是:新装系统后第一件事就把journald的空间上限配置好;日常维护优先跑一次du -sh ~/*给家目录“量体温”;每周末让timer自动跑一遍安全清理脚本;每个月手动检查一次Docker和开发工具的缓存。这套组合下来,我的好几台服务器和个人笔记本,两年多来没有被磁盘空间问题困扰过。希望对你有帮助,也欢迎在评论分享你自己的清理习惯和踩过的坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询