Linux 中最重要的目录之 /proc

https://mp.weixin.qq.com/s/8Nr0yCa2QreMONR1zCUcAA

概述

Linux 系统中,一切皆为文件的理念[1]提供了最高级的抽象,开发者只需要使用一套 API 就可以操作 Linux 系统中的绝大部分资源。

而在整个 Linux 目录树中, 有一个最重要的 (虚拟) 目录: /proc ,在系统启动时创建,在系统关闭时销毁。

内核态通过简洁的文件内容 API 形式,将系统的大部分状态在用户态充分暴露出来,这样用户/程序直接读取 /proc 目录下面的相关文件,就可以获取到对应的系统/进程等状态和数据,真可谓大道至简。

总之,想要知道当前系统中运行了哪些进程、每个进程都打开了哪些文件、进程的 CPU、内存等使用情况如何、每个进程启动了几个线程、当前有哪些 TCP/UDP 连接、每个网卡收发的字节数等等,都可以在 /proc 目录中找到答案。

BTW, 直接读取 /proc 目录下面的文件内容,也是很多 Linux 常用命令和开源系统监控组件的实现原理。

本文主要从开发者使用 Linux 系统的角度,着重分析一下 /proc 目录下可以获取到的四类信息:

  1. 系统

  2. 硬件/设备

  3. 网络

  4. 进程


系统相关

内核版本/编译器/编译时间

$ cat /proc/versionLinux version 6.6.87+ (builder@f33bfd62b873) (Chromium OS 17.0_pre498229-r33 clang version 17.0.0 (/var/cache/chromeos-cache/distfiles/egit-src/external/github.com/llvm/llvm-project 14f0776550b5a49e1c42f49a00213f7f3fa047bf), LLD 17.0.0) #1 SMP PREEMPT_DYNAMIC Sat May  3 09:33:57 UTC 2025

可以看到,输出的信息远比 uname 命令获取到内容要详细。

$ uname -aLinux cs-100667547897-default 6.6.87+ #1 SMP PREEMPT_DYNAMIC Sat May  3 09:33:57 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

系统负载

输出系统最近 1/5/15 分钟的平均负载。

$ cat /proc/loadavg0.03 0.01 0.00 1/300 1272

对比 uptime 命令的输出

$ uptime14:12:36 up  7:44,  0 user,  load average: 0.03, 0.01, 0.00

硬中断

输出系统中的硬件中断情况,按照 CPU 进行分组。

$ cat /proc/interrupts# output           CPU0       CPU1  0:        269          0   IO-APIC   0-edge      timer  1:          0          9   IO-APIC   1-edge      i8042  4:          0       2067   IO-APIC   4-edge      ttyS0  6:         70          0   IO-APIC   6-edge  8:          0          0   IO-APIC   8-edge      rtc0  9:          0          0   IO-APIC   9-fasteoi   acpi 10:          0      16876   IO-APIC  10-fasteoi   virtio2...

软中断

输出系统中的硬件中断情况,按照 CPU 进行分组。

$ cat /proc/softirqs# output                    CPU0       CPU1          HI:          0          0       TIMER:      98735      84868      NET_TX:          2          4      NET_RX:      18737      28301       BLOCK:          0      29051    IRQ_POLL:          0          0     TASKLET:         44         30       SCHED:     200114     198635     HRTIMER:          0          0         RCU:      57886      61736

每个 CPU 都对应一个软中断内核线程运行状况,所以使用下面的命令,也可以获取到 CPU 软中断运行情况。

$ ps aux | grep softirq

内核参数

通过读写文件来动态调整内核参数,例如在TCP 100 万长连接的参数调优[2] 一文中,就涉及到很多 /proc/sys 目录下面相关文件的参数修改,限于篇幅,这里不再赘述了。


硬件相关

CPU

输出机器上所有 (逻辑) CPU 型号、核心数、频率等详细信息。

$ cat /proc/cpuinfoprocessor       : 0vendor_id       : GenuineIntelcpu family      : 6...processor       : 1vendor_id       : GenuineIntelcpu family      : 6...

可以在此基础上计算出 (逻辑) CPU 的数量。

$ cat /proc/cpuinfo | grep processor | wc -l

常用的 Linux 命令中的 lscpu ,输出的源数据就来自 /proc/meminfo 文件。

内存

输出机器上物理内存、交换分区、缓存等信息。

$ cat /proc/meminfoMemTotal:        8138112 kBMemFree:         6372192 kBMemAvailable:    7426484 kBBuffers:           74336 kBCached:          1177368 kBSwapCached:            0 kB...

常用的 Linux 命令中的 freetop ,输出的源数据就来自 /proc/meminfo 文件。

$ free               total        used        free      shared  buff/cache   availableMem:         8138112      711636     6372192        1108     1301156     7426476Swap:              0           0           0

网络相关

网卡数据统计

输出网卡接口的统计信息,例如发送数据量、接收数据量、错误数量。

$ cat /proc/net/devInter-|   Receive                                                |  Transmit face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed    lo: 31272563   12256    0    0    0     0          0         0 31272563   12256    0    0    0     0       0          0  eth0: 6263742   24376    0    0    0     0          0         0 18041254   18792    0    0    0     0       0          0docker0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

常用的 ifconfig 命令,数据源就是 /proc/net/dev 文件。

$ ifconfigdocker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1460        ...        RX packets 0  bytes 0 (0.0 B)        RX errors 0  dropped 0  overruns 0  frame 0        TX packets 0  bytes 0 (0.0 B)        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1460        ...        RX packets 24328  bytes 6256091 (6.2 MB)        RX errors 0  dropped 0  overruns 0  frame 0        TX packets 18758  bytes 18034626 (18.0 MB)        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536        ...        RX packets 12216  bytes 31268081 (31.2 MB)        RX errors 0  dropped 0  overruns 0  frame 0        TX packets 12216  bytes 31268081 (31.2 MB)        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

网络连接状态和对列

输出 TCP/UDP 网络连接,及其对应的端口号和状态等信息。

$ cat /proc/net/tcp$ cat /proc/net/udp

常用的 Linux 网络命令中, netstatss 命令就是对 /proc/net/tcp/proc/net/udp/proc/net/raw 等文件内容进行了二次加工,具体的过程这里就不展开了 :slight_smile:

下面是使用 netstatss 命令的输出结果

$ netstat -ant

$ ss -ant

ARP 表

ARP 表存储着当前局域网中各主机的 IP 地址到 MAC 地址的映射关系[3]。

$ cat /proc/net/arpIP address       HW type     Flags       HW address            Mask     Device10.88.0.1        0x1         0x2         12:a5:12:b7:15:70     *        eth0

下面是对等的 arp 命令。

$ arp -an? (10.88.0.1) at 12:a5:12:b7:15:70 [ether] on eth0

进程相关

每个进程都有一个进程 ID (数字) pid ,所以和进程相关的信息都在目录 /proc/{pid} 下面。

例如下面展示了 root 用户打开的相关进程:

...dr-xr-xr-x   9 root       root                     0 May 19 23:19 207/dr-xr-xr-x   9 root       root                     0 May 19 23:19 25/dr-xr-xr-x   9 root       root                     0 May 19 23:19 26/dr-xr-xr-x   9 root       root                     0 May 19 23:19 264/dr-xr-xr-x   9 root       root                     0 May 19 23:20 270/dr-xr-xr-x   9 root       root                     0 May 19 23:19 271/dr-xr-xr-x   9 root       root                     0 May 19 23:20 275/dr-xr-xr-x   9 root       root                     0 May 19 23:19 285/dr-xr-xr-x   9 root       root                     0 May 19 23:19 296/dr-xr-xr-x   9 root       root                     0 May 19 23:20 467/...

下文的示例中,统一以笔者机器上运行的 dockerd 进程为例,进行代码和命令输出结果演示。

root   207  1  0 23:19 ?        00:00:00 /usr/bin/dockerd -p /var/run/docker.pid --mtu=1460

演示 docker 进程 pid = 207

启动参数

输出进程的启动命令及其参数。

$ sudo cat /proc/207/cmdline/usr/bin/dockerd-p/var/run/docker.pid--mtu=1460

进程状态

输出进程的 pid、ppid、内存使用等信息。

$ sudo cat /proc/207/status# outputName:   dockerdUmask:  0022State:  S (sleeping)Tgid:   207Ngid:   0Pid:    207PPid:   1...Threads:        10...Cpus_allowed:   3Cpus_allowed_list:      0-1Mems_allowed:   00000000,00000001Mems_allowed_list:      0...

函数调用栈

输出进程当前正在执行的的函数调用栈。

$ sudo cat /proc/207/stack# output[<0>] futex_wait_queue+0xdd/0x130[<0>] futex_wait+0x179/0x300[<0>] do_futex+0x18f/0x1e0[<0>] __se_sys_futex+0x152/0x1d0[<0>] do_syscall_64+0x46/0xb0[<0>] entry_SYSCALL_64_after_hwframe+0x78/0xe2

线程状态

输出进程

$ sudo ls -l /proc/207/task/# outputtotal 0dr-xr-xr-x 7 root root 0 May 20 13:43 206dr-xr-xr-x 7 root root 0 May 20 13:44 212dr-xr-xr-x 7 root root 0 May 20 13:44 213dr-xr-xr-x 7 root root 0 May 20 13:44 214dr-xr-xr-x 7 root root 0 May 20 13:44 215dr-xr-xr-x 7 root root 0 May 20 13:44 221dr-xr-xr-x 7 root root 0 May 20 13:44 229dr-xr-xr-x 7 root root 0 May 20 13:44 249dr-xr-xr-x 7 root root 0 May 20 13:44 263dr-xr-xr-x 7 root root 0 May 20 13:44 275

下面是使用 pstree 命令输出的线程结果。

$ pstree -p 207

打开文件

输出 dockerd 进程打开的所有文件句柄 (fd)。

$ sudo ls -l /proc/207/fd/

内存映射

输出进程内存映射区域(例如堆、共享库),smaps 细化到每个区域的 RSS 和脏页统计,用于内存泄漏分析 (具体的分析方法,感兴趣的读者可以自行搜索)。

$ sudo cat /proc/212/maps

$ sudo cat /proc/212/smaps

会逐行输入类似如下的内存映射信息:

Linux 命令中的 pmap 的数据源就是 maps 和 smaps 文件。

$ sudo pmap -x 207

OOM

Linux 内核 OOM killer 会在内存不足时,选择性地杀掉用户进程。

它的运行规则简单来说就是,OOM killer 会为每个用户进程设置一个权重值,这个权重值越高,被 kill 的概率越高,反之概率越低。

每个进程的权重值存放在 /proc/{pid}/oom_adj 中,大多数进程的默认权重值都是 0。

$ sudo cat /proc/207/oom_adj

网络连接

进程网络相关的文件都在 /proc/{pid}/net 目录下面,可以根据不同的协议类型查看对应的文件,输出结果和 /proc/net/ 下面的文件基本类似,限于篇幅,这里就不再赘述了。


小结

1 个赞