我正在开发一个在Linux中监控进程资源并周期性报告的应用程序,但是我在提取每个进程打开的文件计数时遇到了问题。
如果我将所有文件按其PID分组并计数,则需要相当长的时间。
如何获取Linux中每个进程的打开文件计数?
看一下 /proc/
文件系统:
ls /proc/$pid/fd/ | wc -l
要为所有进程执行此操作,请使用以下内容:
cd /proc
for pid in [0-9]*
do
echo "PID = $pid with $(ls /proc/$pid/fd/ | wc -l) file descriptors"
done
作为一个单行命令(通过添加| grep -v "0 FDs"进行过滤):for pid in /proc/[0-9]*; do printf "PID %6d has %4d FDs\n" $(basename $pid) $(ls $pid/fd | wc -l); done
作为一个一行命令,按文件描述符计数降序排序(通过在结尾添加 | head -10
限制结果数量):for pid in /proc/[0-9]*; do p=$(basename $pid); printf "%4d FDs for PID %6d; command=%s\n" $(ls $pid/fd | wc -l) $p "$(ps -p $p -o comm=)"; done | sort -nr
感谢@Boban提供的这个补充:
你可以将上述脚本的输出导入下面的脚本,以查看打开最多文件描述符的十个进程(以及它们的名称):
...
done | sort -rn -k5 | head | while read -r _ _ pid _ fdcount _
do
command=$(ps -o cmd -p "$pid" -hc)
printf "pid = %5d with %4d fds: %s\n" "$pid" "$fdcount" "$command"
done
这是另一种列出打开文件描述符最多的前十个进程的方法,可能不太易读,因此我没有放在前面:
find /proc -maxdepth 1 -type d -name '[0-9]*' \
-exec bash -c "ls {}/fd/ | wc -l | tr '\n' ' '" \; \
-printf "fds (PID = %P), command: " \
-exec bash -c "tr '\0' ' ' < {}/cmdline" \; \
-exec echo \; | sort -rn | head
for pid in [0-9]*; do echo "PID = $pid with $(ls /proc/$pid/fd/ 2>/dev/null | wc -l) file descriptors"; done | sort -rn -k5 | head | while read -r line; do pid=
echo $line | awk '{print $3}'; command=
ps -o cmd -p $pid -hc; echo $line | sed -s "s/PID = \(.*\) with \(.*\)/Command $command (PID = \1) with \2/g"; done
。 - Boban P.ps
查找其命令,更有意义的做法可能是在第一个循环中使用 /proc/$pid/cmdline
。虽然从技术上讲,在评估 [0-9]*
和扫描其磁盘之间,进程仍然有可能消失,但这种情况不太可能发生。 - Alfecommand=$(ps -o cmd -p "$pid" -hc)
给我返回了 Warning: bad syntax, perhaps a bogus '-'
。但是在运行时,使用 command=$(ps -o cmd -p "$pid" hc)
是可以正常工作的。 - Lucas Basquerotto试试这个:
ps aux | sed 1d | awk '{print "fd_count=$(lsof -p " $2 " | wc -l) && echo " $2 " $fd_count"}' | xargs -I {} bash -c {}
我使用了这个方法来查找给定用户(用户名)的顶级文件处理程序消耗进程,因为我没有lsof或root访问权限:
for pid in `ps -o pid -u username` ; do echo "$(ls /proc/$pid/fd/ 2>/dev/null | wc -l ) for PID: $pid" ; done | sort -n | tail
procpath query -f stat,fd
如果您是以root身份运行它的(例如,在命令前加上sudo -E env PATH=$PATH
),否则它将仅返回每个进程的文件描述符计数,您可以列出其/proc/{pid}/fd
。这将给您一个大的JSON文档/树,其节点看起来像:
{
"fd": {
"anon": 3,
"blk": 0,
"chr": 1,
"dir": 0,
"fifo": 0,
"lnk": 0,
"reg": 0,
"sock": 3
},
"stat": {
"pid": 25649,
"ppid": 25626,
...
},
...
}
fd
字典的内容是每种文件描述符类型的计数。其中最有趣的可能是这些(有关更多详细信息,请参见procfile.Fd说明或man fstat):
reg
- 打开(常规)文件的计数sock
- 打开套接字的计数procpath --logging-level ERROR record -f stat,fd -i 1 -d ff_fd.sqlite \
'$..children[?(@.stat.pid == 2468)]'
# Ctrl+C
procpath plot -q fd -d ff_fd.sqlite -f ff_df.svg
如果我只对某种类型的打开文件描述符(比如套接字)感兴趣,我可以像这样绘制它:
procpath plot --custom-value-expr fd_sock -d ff_fd.sqlite -f ff_df.svg
此处为HTML代码
ps -opid= -ax | xargs -L 1 -I{} -- sudo bash -c 'echo -n "{} ";lsof -p {} 2>/dev/null | wc -l' | sort -n -k2
numopenfiles
对每个pid
进行排序打印。
man lsof
- BMW