linux的proc文件系统(procfs)的全称是process information pseudo-filesystem(进程信息伪文件系统)。它是一个虚拟的文件系统,通常在系统启动时被自动挂载到/proc目录,以一个多级的目录/文件的方式显示关于进程和其它的系统信息。
proc文件系统中的绝大多数文件是只读的,但也有一些是可写的(例如/proc/sys)。
proc文件系统提供了从用户空间通往内核空间的一个入口,通过读取其中的文件来动态地获得内核的状态。很多Linux系统命令,比如lsmod、ps,都是通过直接访问proc文件系统来获得数据。此外还可以通过修改某些文件的内容来改变内核参数。
与一般的文件系统存储在磁盘上不同,procfs存在于内存中。因而你会发现/proc目录下的文件大小都是0(除了kcore、mtrr、self);并且对文件的修改也不会被持久化(比如通过sysctl修改内核参数在重启后会失效)。
进程信息
Linux为系统中运行的每一个进程在/proc下创建了一个子目录——/proc/PID,PID为进程ID。
这些子目录包含了所对应的进程的信息,包括:
- /proc/PID/cmdline 最初启动进程的命令,比如在下面的例子中,7588是一个java进程
# cat /proc/7588/cmdline
java -Djava.security.egd=file:/dev/./urandom -jar demo-ui-0.20.1-SNAPSHOT.jar
- /proc/PID/cwd 指向进程当前工作目录的符号链接(symbolic link)
# ls -lt /proc/7588/cwd
lrwxrwxrwx 1 root root 0 Jan 19 06:33 /proc/7588/cwd -> /app # 7588进程的工作目录是/app
- /proc/PID/environ 进程的环境变量
- /proc/PID/exe 指向进程可执行文件的符号链接(symbolic link),例如:
# ls -lh /proc/7588/exe
lrwxrwxrwx 1 root root 0 Dec 10 17:32 /proc/7588/exe -> /usr/lib/jvm/java-8-oracle/bin/java
- /proc/PID/fd 这个目录包含了指向进程中每一个打开的文件描述符的符号链接(链接名就是文件描述符的编号),例如:
# ls -ltr /proc/7588/fd
total 0
lr-x------ 1 root root 64 Jan 18 14:36 9 -> /dev/urandom
lr-x------ 1 root root 64 Jan 18 14:36 8 -> /usr/lib/jvm/java-8-oracle/jre/lib/jsse.jar
l-wx------ 1 root root 64 Jan 18 14:36 7 -> /root/.mofa/logs/_logs_/default/local-demo-ui-0.log
l-wx------ 1 root root 64 Jan 18 14:36 6 -> /root/.mofa/logs/_logs_/default/local-demo-ui-0.error
lrwx------ 1 root root 64 Jan 18 14:36 59 -> anon_inode:[eventpoll]
l-wx------ 1 root root 64 Jan 18 14:36 58 -> pipe:[48487]
lr-x------ 1 root root 64 Jan 18 14:36 57 -> pipe:[48487]
lrwx------ 1 root root 64 Jan 18 14:36 56 -> anon_inode:[eventpoll]
lrwx------ 1 root root 64 Jan 18 14:36 50 -> socket:[48484]
...
- /proc/PID/fdinfo 在这个目录中,每一个打开的文件描述符有一个对应的文件,内容包括对应文件的一些信息,比如:
# cat /proc/7588/fdinfo/30
pos: 0 # 文件offset
flags: 04001 # 文件flags
mnt_id: 10 # 包含这个文件的挂载点ID
- /proc/PID/maps 这个文件包含了当前映射的内存区域。
- /proc/PID/mem 进程的内存
- /proc/PID/root 指向这个进程根目录的符号链接,通常就是“/”。例如:
# ls -lt /proc/7588/root
lrwxrwxrwx 1 root root 0 Jan 18 09:38 root -> /
- /proc/PID/status 进程的状态信息,包括:
# cat /proc/7588/status
Name: java # 进程运行的指令
State: S (sleeping) # 进程当前的状态,"R (running)", "S (sleeping)", "D (disk sleep)", "T (stopped)", "T(tracing stop)", "Z (zombie)", "X (dead)"
Tgid: 7588 # 线程组ID,一般就是进程ID
Ngid: 0 # NUMA group ID
Pid: 7588 # 进程ID
PPid: 7565 # 父进程ID
TracerPid: 0 # PID of process tracing this process (0 if not being traced).
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256
Groups: 0 1 2 3 4 6 10 11 20 26 27
NStgid: 7588 1
NSpid: 7588 1
NSpgid: 7588 1
NSsid: 7588 1
VmPeak: 5637656 kB
VmSize: 5637656 kB # 系统为进程分配的虚拟内存的大小 ,有关进程内存,详情参考:https://blog.csdn.net/sinat_26058371/article/details/86536213
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 1029820 kB # RSS的峰值大小
VmRSS: 1029820 kB # RSS大小
VmData: 5581264 kB # 数据大小
VmStk: 132 kB # 栈大小
VmExe: 4 kB # text segment大小
VmLib: 18240 kB # 共享库代码大小
VmPTE: 2320 kB
VmPMD: 36 kB
VmSwap: 0 kB # 交换分区的大小
HugetlbPages: 0 kB
Threads: 41 # 进程中线程的数量
SigQ: 0/31353
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 2000000181005ccf
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
Seccomp: 0
Cpus_allowed: f # 这个进程能够运行的CPU掩码,这台机器的CPU有4个核心,f(1111)表示这个进程可以在所有核心上运行
Cpus_allowed_list: 0-3 # 这个进程能够运行在那些cpu上,cpu的id是一个数组,通常范围是0 ~ cpu核数-1(这里就是0、1、2、3)
Mems_allowed: 00000000,00000001 # 这个进程能够访问的内存节点掩码(和NUMA的group id一致)
Mems_allowed_list: 0 # 这个进程能够访问的内存节点(和NUMA的group id一致)
voluntary_ctxt_switches: 56
nonvoluntary_ctxt_switches: 5
- /proc/PID/task 这个目录中,进程中的每一个线程都有一个对应的子目录,子目录名就是线程ID,子目录中的文件结构与/proc/PID目录中的一致。例如:
# ls /proc/7588/task/7642
attr children comm environ fdinfo limits mem net oom_adj pagemap root sessionid stack status wchan
auxv clear_refs cpuset exe gid_map loginuid mountinfo ns oom_score personality sched setgroups stat syscall
cgroup cmdline cwd fd io maps mounts numa_maps oom_score_adj projid_map schedstat smaps statm uid_map
- /proc/PID/ns 包含进程所属的各个namespaces的文件描述符。例如:
# ls /proc/7588/ns
total 0
lrwxrwxrwx 1 root root 0 Feb 27 10:26 uts -> uts:[4026531838]
lrwxrwxrwx 1 root root 0 Feb 27 10:26 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Feb 27 10:26 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Feb 27 10:26 net -> net:[4026531968]
lrwxrwxrwx 1 root root 0 Feb 27 10:26 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Feb 27 10:26 ipc -> ipc:[4026531839]
- /proc/self 指向程序自己的进程目录。比较拗口,举个例子,比如两个程序的进程ID分别是123和456,这两个程序都访问/proc/self目录,那么它们实际访问的目录分别为/proc/123和/proc/456。
进程相关的命令
Linux中的查询进程最常用命令ps就是通过读取proc文件系统来获得进程信息的。
在了解了/proc/PID中各个文件的含义后,我们也可以通过直接访问文件的方式来获得进程信息。例如
$ readlink /proc/$(pgrep -n java)/exe # 找到最后运行的Java程序的java可执行文件的路径
/usr/lib/jvm/java-8-oracle/bin/java
$ cat /proc/7588/status | grep VmSize # 获得7588号进程所使用的内存
VmRSS: 2947192 kB
其它系统信息
起初procfs只提供进程(process)相关的信息,这也是它的名字的由来。但之后Linux又向里加入了一些与进程无关的其它一些系统信息。在2.6内核中,很多信息被挪到了另一个文件系统——sys(在之后一篇文章中会单独介绍)。
proc文件系统提供的主要系统信息包括:
- /proc/cpuinfo 主机的cpu信息。下面是在一台4核主机上的/proc/cpuinfo的内容:
# cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 79
model name : Intel(R) Xeon(R) CPU E5-26xx v4
stepping : 1
microcode : 0x1
cpu MHz : 2394.454
cache size : 4096 KB
physical id : 0
siblings : 4
core id : 0
cpu cores : 4
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx lm constant_tsc rep_good nopl eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch bmi1 avx2 bmi2 rdseed adx xsaveopt
bugs :
bogomips : 4788.90
clflush size : 64
cache_alignment : 64
address sizes : 40 bits physical, 48 bits virtual
power management:
processor : 1
...
processor : 2
...
processor : 3
...
- /proc/meminfo 系统的内存使用信息,包含物理内存和swap分区。free命令就是读取这个文件。例如:
# cat /proc/meminfo
MemTotal: 8043944 kB
MemFree: 1834160 kB
MemAvailable: 4329456 kB
Buffers: 491388 kB
Cached: 2091380 kB
SwapCached: 0 kB
Active: 4260852 kB
Inactive: 1370900 kB
Active(anon): 3055416 kB
Inactive(anon): 34128 kB
Active(file): 1205436 kB
Inactive(file): 1336772 kB
Unevictable: 3660 kB
Mlocked: 3660 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 1228 kB
Writeback: 0 kB
AnonPages: 3052880 kB
Mapped: 520800 kB
Shmem: 38140 kB
Slab: 463060 kB
SReclaimable: 257024 kB
SUnreclaim: 206036 kB
KernelStack: 20208 kB
PageTables: 17232 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 4021972 kB
Committed_AS: 11174476 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
AnonHugePages: 1994752 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 264184 kB
DirectMap2M: 8124416 kB
- /proc/loadavg 系统的平均负载水平
# cat /proc/loadavg
5.57 5.01 4.91 5/1250 27822
前三个值分别是1、5、15分钟的负载平均值;第四项“5/1250”分别表示当前有5个可运行的进/线程,当前在系统中一共存在1250个进/线程;最后一个值是系统最近创建的进程的PID。
- /proc/modules 当前所加载的内核模块,lsmod命令读取该文件。
- /proc/sys 这个目录包括很多的文件,一个文件对应一个内核参数。每一个文件看上去都是一个普通的文本文件,里面的内容只有一个值(通常就是一个整数),代表参数的值。内核参数的名称都是分段式的,之间用“.”隔开,每一段对应了一级子目录(和java的package机制类似)。比如内核参数net.core.somaxconn对应的文件是“/proc/sys/net/core/somaxconn”。可以通过修改这些文件的内容来设置内核参数,比如:
# echo 65535 > /proc/sys/net/core/somaxconn
- /proc/net 网络相关的信息。内容很多,常用的文件包括:
- /proc/net/arp ARP缓存
# cat /proc/net/arp # arp缓存
IP address HW type Flags HW address Mask Device
10.201.54.252 0x1 0x2 0a:58:0a:c9:36:fc * cbr0
10.201.54.246 0x1 0x2 0a:58:0a:c9:36:f6 * cbr0
10.201.54.248 0x1 0x2 0a:58:0a:c9:36:f8 * cbr0
10.201.54.130 0x1 0x2 0a:58:0a:c9:36:82 * cbr0
- /proc/net/dev 网络设备状态信息
# cat /proc/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
veth38482784: 0 0 0 0 0 0 0 0 504 12 0 0 0 0 0 0
veth5972cf8d: 24146809 293505 0 0 0 0 0 0 147188022 386266 0 0 0 0 0 0
veth148b56dc: 17633628 195860 0 0 0 0 0 0 70001394 197908 0 0 0 0 0 0
bond1: 596288963157 832107276 0 13 0 0 0 2656255 1678252721434 1276200925 0 0 0
- /proc/net/route 路由信息,route指令读取这个文件
# cat /proc/net/route # 路由信息
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
bond1 00000000 0136C90A 0003 0 0 0 00000000 0 0 0
bond1 0036C90A 00000000 0001 0 0 0 00FFFFFF 0 0 0
cbr0 8036C90A 00000000 0001 0 0 0 80FFFFFF 0 0 0
docker0 0000FE0A 00000000 0001 0 0 0 00F0FFFF 0 0 0
bond1 00004064 0136C90A 0003 0 0 0 0000C0FF 0 0 0
bond1 0000FEA9 00000000 0001 0 0 1006 0000FFFF 0 0
- /proc/net/nf_conntrack 当前的网络链接,netstat指令输出的就是这个文件的内容。
# cat /proc/net/nf_conntrack
ipv4 2 tcp 6 95 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=35974 dport=60001 src=127.0.0.1 dst=127.0.0.1 sport=60001 dport=35974 [ASSURED] mark=0 zone=0 use=2
ipv4 2 tcp 6 13 TIME_WAIT src=10.201.54.129 dst=10.201.54.252 sport=42086 dport=8080 src=10.201.54.252 dst=10.201.54.129 sport=8080 dport=42086 [ASSURED] mark=0 zone=0 use=2
ipv4 2 tcp 6 86377 ESTABLISHED src=127.0.0.1 dst=127.0.0.1 sport=60752 dport=60001 src=127.0.0.1 dst=127.0.0.1 sport=60001 dport=60752 [ASSURED] mark=0 zone=0 use=2
...
- /proc/uptime 系统的运行时间
# cat /proc/uptime
3373642.34 7841089.28
3373642.34表示系统已经运行了3373642.34秒(39天左右);7841089.28代表系统空闲的时间(单位秒,大约78天)。之所以空闲的时间比运行的时间还要多,是因为每个cpu核心的空闲时间是单独计算的。上面这台4核主机的空闲率大致为:7841089.28 / 3373642.34 /4 = 58%
- /proc/stat 内核/系统的各种统计数据
- /proc/version 内核版本
# cat /proc/version
Linux version 4.4.0-104-generic (buildd@lgw01-amd64-022) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.5) ) #127-Ubuntu SMP Mon Dec 11 12:16:42 UTC 2017