lsof 入门:找出是谁占着端口和被删除却没释放的文件
服务启动时报 Address already in use,或者明明删掉了一个大日志,df 显示的可用空间却纹丝不动,这两类问题背后都是同一个原因:某个进程还“打开”着它。lsof(list open files)能把进程和它打开的文件、网络连接对应起来。在 Linux 里,监听的端口也算一种打开的文件。下面的进程名、PID 和输出都是人为构造的示例,只由假设场景推导,不是真实机器的测量结果。
一、安装与基本习惯
很多精简镜像默认没有 lsof,可以用包管理器安装:
sudo apt install lsof # Debian / Ubuntu
sudo dnf install lsof # CentOS Stream / Rocky 等
查看其他用户的进程需要 root,否则结果可能不完整,所以排查时通常加 sudo。另外建议习惯性加上 -n 和 -P:前者不把 IP 反解成主机名,后者不把端口号翻译成服务名,输出更快也更直观。
二、谁占用了端口
假设 8080 端口被占,执行:
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN
-iTCP:8080 只看 TCP 的 8080 端口,-sTCP:LISTEN 只保留处于监听状态的条目。示例输出如下:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python3 2345 alice 3u IPv4 31024 0t0 TCP *:8080 (LISTEN)
可以读出:PID 为 2345 的 python3 进程,以 alice 身份在所有地址上监听 8080。FD 列的 3u 表示文件描述符 3,u 代表可读可写。拿到 PID 之后,先用 ps -fp 2345 看完整命令行,确认它是不是一个忘记关掉的旧实例,再决定是正常停服务还是换端口,而不是直接 kill -9。
如果只想拿 PID 用在脚本里,可以加 -t,它只输出进程号:
sudo lsof -t -iTCP:8080 -sTCP:LISTEN
三、删除了文件,空间却没回来
Linux 删除文件只是去掉目录里的名字。只要还有进程打开着它,数据块就不会被释放。用 +L1 可以列出链接数小于 1、也就是已经没有文件名但仍被打开的文件:
sudo lsof -nP +L1
示例输出:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
python3 2345 alice 4w REG 253,1 52428800 0 1310 /tmp/app.log (deleted)
这表示 2345 进程仍以写模式(4w)持有一个约 50MB 的已删除文件。处理方式有两种:
- 最干净的做法是正常重启或重新加载该服务,让它关闭旧文件句柄。
- 暂时不能重启时,可以通过 /proc 把这个句柄对应的文件截断为 0,空间会立即释放:
sudo sh -c ': > /proc/2345/fd/4'
截断会丢掉文件里的内容,执行前要确认这份数据确实不再需要。长远来看,应该用 logrotate 的 copytruncate 或让程序支持重新打开日志,而不是手动 rm 正在写的日志。
四、几个顺手的查询
sudo lsof -p 2345 # 某个进程打开的所有文件
sudo lsof /var/log/app.log # 谁正在使用这个文件
sudo lsof +D /data/tmp # 递归查看目录下被打开的文件,目录大时较慢
如果只关心端口,ss -ltnp 也能给出类似信息;lsof 的优势在于把端口、普通文件和已删除文件放在同一个视角下查看。
- 点赞
- 收藏
- 关注作者
评论(0)