十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Linux垃圾文件清理与磁盘空间释放实战指南

Linux垃圾文件清理与磁盘空间释放实战指南 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 autoremoveaptDebian/Ubuntu系sudo apt-get autoclean只清理过期的安装包dnfFedora/RHEL系sudo dnf clean allsudo dnf autoremovepacmanArch系sudo pacman -Sccsudo pacman -Sc保留最新版本这里有个多数人容易混淆的点apt-get clean和apt-get autoclean到底有什么区别简单来说clean是把缓存目录里所有已下载的deb安装包全部删掉一个不留而autoclean只删除那些已经无法再从软件源下载到的“过期”包还能下载的包保留着。从清理效果来看clean更彻底但如果你的网络环境不太稳定我建议用autoclean保留一份最近安装过的安装包万一软件出问题了还能本地重装。还有一个命令经常被忽略apt-get autoremove。这条命令的作用是把“为了满足依赖而自动安装、但现在不再被任何软件依赖”的包自动移除。系统更新迭代过程中会产生很多这种孤儿依赖我见过一台跑了一年多NginxMySQL的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-time7d # 或者指定日志总大小上限超过自动清理最老的 sudo journalctl --vacuum-size100M在确认journallog清理没问题的同时我建议你直接修改配置来控制未来的增长这样以后不用再频繁手动清理# 编辑journald配置文件 sudo vim /etc/systemd/journald.conf找到SystemMaxUse这一行取消注释并设置上限例如SystemMaxUse200M设置完重启日志服务sudo systemctl restart systemd-journald把日志总大小锁死在200M以内journald会自动轮转和清理旧日志再也不用担心日志撑爆磁盘。这个技巧对服务器运维场景尤其重要——很多线上事故都是日志把磁盘写满导致的。需要特别提醒journal日志和/var/log下的经典文本日志如syslog、auth.log、kern.log并不是一码事。如果你用的是传统rsyslog方案清理姿势是truncate或删除旧日志文件可以参考下面的方式# 清空当前syslog文件而不是删除删除可能导致服务句柄异常 sudo truncate -s 0 /var/log/syslog sudo truncate -s 0 /var/log/auth.log3. 用户家目录与开发环境缓存容易被忽略的“隐形仓库”刚才讲的包管理器和日志是最容易发现的两块“显性垃圾”。但如果你在个人电脑或开发机上做清理真正让磁盘空间悄悄消失的大头其实躺在用户家目录和开发环境里。很多人的根分区没大多少但家目录挂载的分区却经常报警排查下来基本都是这类“隐形缓存”惹的祸。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 -203.2 ~/.cache与用户级临时文件的安全清理确认了占空间大户之后下一步是搞清楚哪些能删。~/.cache这个目录理论上就是给应用程序存临时缓存的地方清掉之后系统不会坏最多是下次打开软件时重新生成缓存。但这里有个坑有一些软件的缓存里保存了未保存的对话记录、草稿之类的数据比如某些编辑器、浏览器扩展。所以稳妥的做法是优先清理那些确定可以重新生成的缓存子目录比如~/.cache/thumbnails系统缩略图缓存删了会重新生成放心删~/.cache/pippip下载的安装包缓存删了不影响已装包~/.cache/mozilla/firefox/.../cache2火狐浏览器的缓存文件清理无风险~/.cache/google-chrome/.../CacheChrome缓存同理对于不确定的子目录我建议用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 --forceyarn~/.cache/yarnrm -rf或yarn cache cleanGo module~/go/pkg/mod/cachego clean -modcache说明此命令用于清理模块缓存Gradle~/.gradle/cachesrm -rf ~/.gradle/caches或使用gradle cleanBuildCacheMaven~/.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 -deleteDocker的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 L1L1的意思就是列出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 DRYfalse # 解析参数 [[ ${1:-} --dry-run ]] DRYtrue 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 21 apt-get autoremove -y /dev/null 21 log apt cache cleaned elif command -v dnf /dev/null; then $DRY { echo [DRY] dnf clean all; return; } dnf clean all /dev/null 21 log dnf cache cleaned elif command -v pacman /dev/null; then $DRY { echo [DRY] pacman -Sc; return; } # 保留最新版本缓存删除过时包缓存 pacman -Sc --noconfirm /dev/null 21 log pacman cache cleaned fi } clean_journal() { $DRY { echo [DRY] journalctl --vacuum-size100M; return; } journalctl --vacuum-size100M /dev/null 21 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 until72h /dev/null 21 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] DescriptionClean system junk files Afternetwork.target [Service] Typeoneshot ExecStart/usr/local/bin/clean-system.sh再创建一个timer文件# /etc/systemd/system/clean-system.timer [Unit] DescriptionRun clean-system weekly [Timer] OnCalendarweekly Persistenttrue [Install] WantedBytimers.target然后启用并启动timersudo systemctl daemon-reload sudo systemctl enable --now clean-system.timer sudo systemctl start clean-system.timer之后每周系统就会自动运行一次清理脚本。想看上次执行时间和结果用systemctl status clean-system.timer或journalctl -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.retain2然后执行sudo snap refresh让系统移除旧版本不要直接删除/var/lib/snapd下的文件否则snap服务会直接报错。浏览器配置文件不要直接删浏览器会把密码、书签、扩展设置都存在~/.config或~/.mozilla目录下这部分不属于缓存删了等于重置浏览器。真正能清的是各个浏览器自己的Cache子目录。home目录下的“隐藏文件夹”先看清楚再动手很多人看到~/.local、~/.config占了大量空间想直接rm -rf这属于重破坏行为。~/.local/share里往往有应用的数据文件比如一些游戏的存档、邮件客户端的本地邮件存储删了不可恢复。个人经验收尾做Linux系统维护这十多年我最深的体会之一是清理垃圾文件这件事本质上是在给系统“做减法”而这个减法最难的地方不在于“删”而在于“判断”。判断哪些是垃圾、哪些是数据判断哪些能自动清理、哪些必须留给人来决策这比记住几条命令重要得多。我现在的习惯是新装系统后第一件事就把journald的空间上限配置好日常维护优先跑一次du -sh ~/*给家目录“量体温”每周末让timer自动跑一遍安全清理脚本每个月手动检查一次Docker和开发工具的缓存。这套组合下来我的好几台服务器和个人笔记本两年多来没有被磁盘空间问题困扰过。希望对你有帮助也欢迎在评论分享你自己的清理习惯和踩过的坑。
返回列表