linux lsof加-p和不加-p的区别(第一次用就被坑难受)

本文通过实例分析了Linux中使用lsof命令统计进程文件句柄数的情况,探讨了-p参数指定进程与不指定的区别。在解决系统资源占用问题时,发现一个进程的文件句柄数与其线程数有关,每个线程共享打开的文件,导致统计结果差异。通过统计线程数和每个线程的文件句柄重复次数,得出结论:进程的文件句柄数应考虑其线程共享资源的因素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

针对以下两条命令,先给自己的结论吧:加-p是指定进程,不加-p的是线程

(脚本小白,没找着出处,是根据数据观察的,欢迎各位大佬指正)

 

最近,系统出了一次问题,导致所有页面都打不开,接口都访问失败,当然作为运维小白,显然是不咋会看Linux的一些资源占用情况的,然后看了提交记录没改啥影响全局的东西,就埋头去看错误日志了,额,,,显然错误日志也不少,还没在错误日志的信息里提取出主要原因,大佬就说:我看了一下,文件句柄数超过默认的1024了。你看看是不是这个原因,果然日志文件里:java.io.IOException:Too many open files。然后就自己检查哪些打开流没关的,问题解决。

很久之后,领导:最近系统很慢啊,你把Linux的一些资源占用情况定时入库吧。我嘴上:好的。内心:这是要写jio本吗?我不会吖?╥﹏╥...。然后就开始各种翻博客,cpu、内存啥啥的,查到了,嗯,用top很顺利,优秀的文章又多,终于,到了文件句柄了,基本上都是:

统计各进程打开句柄数(执行结果:第一列是数量,第二列是pid):

lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|more

统计单个进程打开句柄数(执行结果:只有数量):

lsof -p pid |wc -l

执行:

[root@localhost ~]# lsof -p 11211 |wc -l
437
[root@localhost ~]# lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|more
  90688 11211
  46368 11055
  ...

这,不对啊,指定pid统计结果437,不指定pid统计结果90688,就算它时刻在变化,复制粘贴前后时间相差一秒,也没这么大变化吧,我网上搜啊搜啊,也搜不出为啥,不会是文件句柄打开没关导致泄露吧,跟领导汇报完,领导:不可能,60%都是你危言耸听,你再查查看。网上我是搜不到了,然后就把详细信息打出来对比了:

[root@localhost ~]# lsof -p 11211
COMMAND   PID USER   FD      TYPE             DEVICE  SIZE/OFF      NODE NAME
java    11211 root  cwd       DIR              253,0        64 101221120 /n....
java    11211 root  rtd       DIR              253,0       281        64 /
java    11211 root  txt       REG              253,0      7734 100879130 /usr/...
....
#脚本大意:输出包含11211的行(不是很会脚本,表头是我单独执行lsof复制过来的,尴尬)
[root@localhost ~]# lsof |grep 11211
COMMAND     PID   TID      USER   FD      TYPE    DEVICE     SIZE/OFF     NODE NAME
java      11211            root  231u     IPv6    128887212       0t0     TCP localhost...
java      11211            root  232u     IPv6    128887213       0t0     TCP localhost...
java      11211            root  233u     IPv6    128886515       0t0     TCP localhost...
java      11211            root  234r      REG    253,0   3866653  102282 /usr/java/....
java      11211            root  235r      REG    253,0   2245827  102282 /usr/java/....
java      11211            root  236u     unix    0xfff       0t0  128879 socket
java      11211            root  237u     unix    0xfff       0t0  128879 socket
java      11211 11212      root  cwd       DIR    253,0        64  101221 /n..
java      11211 11212      root  rtd       DIR    253,0       281      64 /
...

乍一看,这不一样的吗,再仔细看,咦,第二个多了一列,第三列的TID(线程ID),然后统计了一下TID的重复次数:

#脚本大致意思:只输出包含11211的行,读出每行的第三列,统计相同TID出现次数,排序
[root@localhost ~]# lsof |grep 11211 |awk '{print $3}'|sort|uniq -c |sort -nr|more
    436 root
    436 28785
    436 28784
    436 18749
    436 18748
    436 18747
    436 18746
    436 18741
    436 18740
    436 18699
    436 18698
    436 18697
    ...

欸,你发现没,每个线程重复次数都是一样的,这表明什么,不晓得,但是这么一致肯定是有问题的,再回想一下,当年葛大爷(教操作系统的最严厉的老师)的话:进程持有资源,线程基本不持有资源,共享进程所持有的资源。再翻了一下,找到一张图(有时候图会显示不出来,手动转成了表格):

一般情况下线程共享与独享资源的划分

线程共享

线程独享

地址空间程序计数器
全局变量寄存器
打开的文件
子进程状态字
闹钟 
信号及信号服务成勋 
记账信息 

其他的看不懂没关系,但是我看到了 打开的文件 属于 线程共享 ,再统计这个进程的线程数:

#统计11211进程的线程数
[root@localhost ~]# ps -T -p 11211 |wc -l
209

436*209不就约等于9万多,啊~~~~意思是每个打开文件算是线程共享,所以一个进程有多少个线程就重复了多少次?自我感觉大概就是这意思吧(小声逼逼:虽然也不晓得对不对,毕竟脚本小白,也没找着出处)

好了,根据以上我的结论是:

lsof -p 18088 |wc -l这个脚本统计的是指定进程的文件句柄打开数

lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|more这个脚本我当然不敢说是错的,但不是我想要的,起码如果进程不是只有单个线程的话,不是统计的各进程打开句柄数

 

### lsof 命令及其参数 -i、-n -P 的用法与解释 `lsof` 是 Linux Unix 系统中用于列出当前系统打开文件的命令。在这些系统中,几乎所有内容都被视为文件,包括网络连接、进程、设备等。因此,`lsof` 可以用来查看哪些进程打开了哪些文件或网络端口。 以下是 `lsof` 命令结合 `-i`、`-n` `-P` 参数的具体用法解释: #### 参数说明 1. **`-i` 参数** 该参数用于显示涉及网络的打开文件,并可以指定协议端口号。例如: ```bash sudo lsof -i tcp:80 ``` 上述命令会列出所有使用 TCP 协议并监听 80 端口的进程[^1]。 2. **`-n` 参数** 默认情况下,`lsof` 会将 IP 地址解析为对应的主机名。如果添 `-n` 参数,则会禁用这种解析,直接显示 IP 地址,从而快命令执行速度。例如: ```bash sudo lsof -i -n ``` 3. **`-P` 参数** 默认情况下,`lsof` 会将端口号解析为服务名称(如 80 被解析为 http)。如果添 `-P` 参数,则会禁用这种解析,直接显示端口号。例如: ```bash sudo lsof -i -P ``` #### 综合使用示例 以下是一个综合使用 `-i`、`-n` `-P` 参数的示例,用于查找监听特定端口的所有进程: ```bash sudo lsof -i -n -P | grep LISTEN ``` 上述命令会列出所有处于监听状态的网络连接,并显示其对应的 IP 地址端口号,而不进行主机名或服务名的解析。 #### 示例输出解释 假设运行以下命令: ```bash sudo lsof -i -n -P | grep ":80" ``` 可能的输出如下: ``` nginx 12345 root 6u IPv4 123456 0t0 TCP *:80 (LISTEN) nginx 12345 www-data 7u IPv4 123457 0t0 TCP 192.168.1.1:80->192.168.1.2:12345 (ESTABLISHED) ``` - 第一列:进程名称(如 `nginx`)。 - 第二列:进程 ID(PID)。 - 第三列:用户(如 `root` 或 `www-data`)。 - 第四列:文件描述符类型(如 `6u` 表示读写模式的文件描述符)。 - 第五列:协议类型(如 `IPv4` 或 `IPv6`)。 - 第六列:文件编号。 - 第七列:连接状态(如 `LISTEN` 或 `ESTABLISHED`)。 #### 注意事项 - 使用 `lsof` 命令时通常需要超级用户权限(即 `sudo`),因为某些信息可能涉及系统级资源。 - 如果需要更详细的输出,可以结合其他参数,例如 `-p` 指定进程 ID 或 `-c` 指定进程名称。 ```bash sudo lsof -i -n -P -p 12345 ``` 上述命令会列出 PID 为 12345 的进程所打开的所有网络连接。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值