lsof +l1 是唯一直接有效的方式,它专用于筛选 link count 为 0 的已删除但仍被进程持有的文件,需加 sudo 才能查看所有用户进程,输出中 name 列带 (deleted) 后缀、size/off 显示占用字节数。

lsof +L1 是唯一直接有效的方式
普通 lsof 默认不显示已删除文件,因为路径已不存在;lsof +L1 才是专为此设计的选项——它筛选 link count 为 0 的打开文件,即已被 unlink() 但 fd 仍被进程持有的文件。
执行时必须加 sudo,否则看不到其他用户的进程句柄:
sudo lsof +L1
输出中关键字段:NAME 列带 (deleted) 后缀、SIZE/OFF 显示当前占用字节数、PID 和 COMMAND 告诉你谁在拖着它。若只查某目录(如 /var/log),可加路径限定:
sudo lsof +L1 /var/log
注意:+L1 在旧版 lsof(如 RHEL6 自带)中可能不支持,此时退而求其次:
sudo lsof | grep 'deleted$'
但该方式易误匹配路径含 deleted 字样的正常文件,可靠性不如 +L1。
为什么 lsof | grep deleted 有时找不到目标
不是所有“已删未释放”都会出现在 grep deleted 结果里——比如进程用 mmap() 映射文件后删除,或子进程继承了 fd 但父进程已退出,lsof 可能无法关联到原始路径。
这时得绕过 lsof,直接翻 /proc:
sudo find /proc/[0-9]*/fd -ls 2>/dev/null | grep deleted- 或更轻量:
sudo ls -l /proc/*/fd/ 2>/dev/null | grep deleted | head -10
每条输出形如 /proc/1234/fd/5 -> /var/log/app.log (deleted),其中 1234 是 PID,5 是 fd 编号——这比 lsof 更底层、更可靠。
确认该句柄是否真正在吃磁盘空间
看到 (deleted) 不代表它占了几 GB;有些 fd 是只读打开、早已 EOF,实际不写入;有些则持续追加,空间越滚越大。
验证真实占用大小,两个方法最准:
-
sudo du -sh /proc/1234/fd/5—— 直接统计该 fd 指向内容的磁盘用量 -
sudo ls -lh /proc/1234/fd/5—— 看软链目标是否显示 size(部分内核版本会显示)
如果 du 返回几百 MB 或几个 GB,且 lsof 输出中 SIZE/OFF 列数值相近,那基本就是罪魁祸首。别光看 (deleted) 就动手,先确认它是不是真在撑满磁盘。
别急着 kill,先看进程类型再决定操作
很多线上服务(nginx、rsyslog、java 应用)支持平滑重载日志,直接 kill -9 会中断服务,还可能丢数据。
优先尝试信号重载:
- rsyslog / syslog-ng:
sudo kill -HUP 1234 - nginx:
sudo kill -USR1 1234 - systemd 日志服务:
sudo systemctl kill --signal=USR1 systemd-journald
若进程不支持重载,且确认可中断,再考虑 sudo systemctl restart servicename 或 sudo kill 1234(非 -9)。只有在紧急腾空间且无其他选择时,才用 echo > /proc/1234/fd/5 清空——这不会释放 inode,但会把当前数据块置零,后续写入从头开始,风险在于部分应用会因 fd 状态异常而报错。
真正容易被忽略的是容器场景:宿主机上 lsof +L1 看不到容器内进程,得进容器执行 docker exec -it <code>container_id lsof +L1 或查 crictl ps 后定位。











