【进程】利用 Linux 下的 /proc/pid/ 的内容学习进程

1. 进程号

  1. 在计算机中,每一个进程都有一个进程号,进程号类似于一个索引,操作系统就是通过这个进程号快速地找到进程。在 linux 使用 ps -aux 查看进程,可以看到进程号pid
root@swd-Lenovo-G40-80:/proc/4234# ps -aux | more
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1 225368  9136 ?        Ss   10月29   0:02 /sbin/init splash
root         2  0.0  0.0      0     0 ?        S    10月29   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        I<   10月29   0:00 [rcu_gp]
root         4  0.0  0.0      0     0 ?        I<   10月29   0:00 [rcu_par_gp]
root         6  0.0  0.0      0     0 ?        I<   10月29   0:00 [kworker/0:0H-kb]
root         8  0.0  0.0      0     0 ?        I<   10月29   0:00 [mm_percpu_wq]
root         9  0.0  0.0      0     0 ?        S    10月29   0:00 [ksoftirqd/0]
root        10  0.0  0.0      0     0 ?        I    10月29   0:06 [rcu_sched]
root        11  0.0  0.0      0     0 ?        S    10月29   0:00 [migration/0]
root        12  0.0  0.0      0     0 ?        S    10月29   0:00 [idle_inject/0]
root        14  0.0  0.0      0     0 ?        S    10月29   0:00 [cpuhp/0]
root        15  0.0  0.0      0     0 ?        S    10月29   0:00 [cpuhp/1]
root        16  0.0  0.0      0     0 ?        S    10月29   0:00 [idle_inject/1]
....
root       138  0.0  0.0      0     0 ?        S    10月29   0:00 [oom_reaper]
  1. 在上面 1中获取到的进程号,我们就可以去 /proc 中查看进程的具体信息,在 /proc 中每一个数字,就是对应的一个进程的 pid,进入到进程对应的 pid 的进程的文件夹,里面就可以看到进程的具体信息:
root@swd-Lenovo-G40-80:/proc# ls
1     1176  1285  1354  1456  1736  201   28    3479  3708  397   47   8    889  93         cgroups      irq          mtrr           thread-self
10    119   1299  1359  1471  18    21    29    3495  3739  4     543  800  89   933        cmdline      kallsyms     net            timer_list
101   12    1300  1360  1474  187   22    295   35    3750  40    575  802  892  94         consoles     kcore        pagetypeinfo   tty
102   1202  1304  1369  1496  188   223   296   351   38    4000  591  805  9    95         cpuinfo      keys         partitions     uptime
104   1219  1311  137   15    189   226   299   3510  3802  4002  592  806  90   96         crypto       key-users    pressure       version

2. 建立demo 来分析进程

  • 创建一个 demo:
// filename: pmaps1.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
    char *pStr;
    pStr = (char *)malloc(2);
    while (1);		// 死循环
    return 0;
}
  1. 编译:gcc -o pmaps1 pmaps.c
  2. 运行:./pmaps1
  3. 查看进程的 pid(pid 为 4345):``
root@swd-Lenovo-G40-80:/proc# ps -aux | grep pmaps1
swd       4345  100  0.0   4516   808 pts/3    R+   22:34   4:43 ./pmaps1
  1. 进入 /proc/4345cd /proc/4345
  2. 查看该进程的信息:
root@swd-Lenovo-G40-80:/proc/4345# ls
arch_status  clear_refs       cwd      gid_map    maps        net        oom_score_adj  root       smaps         status         uid_map
attr         cmdline          environ  io         mem         ns         pagemap        sched      smaps_rollup  syscall        wchan
autogroup    comm             exe      limits     mountinfo   numa_maps  patch_state    schedstat  stack         task
auxv         coredump_filter  fd       loginuid   mounts      oom_adj    personality    sessionid  stat          timers
cgroup       cpuset           fdinfo   map_files  mountstats  oom_score  projid_map     setgroups  statm         timerslack_ns

可以看到,能够获取到的信息挺多的!具体需要什么信息,就去查找,下面说几个常用的。

3. 几个常用的进程信息

  1. 打开的文件描述符,可以看到,进程打开的文件描述符,其中 99是因为这个进程我是在 vscode 中远程执行的,所以它有一个指向 vscode的文件描述符,0, 1, 2 是进程的标准输入输出,指向设备文件/dev/pts/3
root@swd-Lenovo-G40-80:/proc/4345# cd fd
root@swd-Lenovo-G40-80:/proc/4345/fd# ls
0  1  19  2  20  21  22  23  99

root@swd-Lenovo-G40-80:/proc/4345/fd# ll
total 0
dr-x------ 2 swd swd  0 1031 22:40 ./
dr-xr-xr-x 9 swd swd  0 1031 22:34 ../
lrwx------ 1 swd swd 64 1031 22:47 0 -> /dev/pts/3
lrwx------ 1 swd swd 64 1031 22:47 1 -> /dev/pts/3
l-wx------ 1 swd swd 64 1031 22:47 19 -> /home/swd/.vscode-server/data/logs/20231031T213437/remoteagent.log
lrwx------ 1 swd swd 64 1031 22:47 2 -> /dev/pts/3
l-wx------ 1 swd swd 64 1031 22:47 20 -> /home/swd/.vscode-server/data/logs/20231031T213437/ptyhost.log
lrwx------ 1 swd swd 64 1031 22:47 21 -> /dev/ptmx
lrwx------ 1 swd swd 64 1031 22:47 22 -> /dev/ptmx
lrwx------ 1 swd swd 64 1031 22:47 23 -> /dev/ptmx
l-wx------ 1 swd swd 64 1031 22:47 99 -> /home/swd/.vscode-server/bin/da76f93349a72022ca4670c1b84860304616aaa2/vscode-remote-lock.swd.da76f93349a72022ca4670c1b84860304616aaa2

这个查看文件描述符有什么用呢?可以用来检查进程的文件描述符有没有被释放,这个很重要,我之前在公司做开发,使用了一个开源代码,就通过查看该进程的 /proc/pid/fd 文件夹发现文件描述符泄露。

  1. 虚拟内存分布(通过/proc/pid/maps查看)
    这个也很常见,在面试 C/C++ 岗位的时候,经常会被问到,进程的内存布局。首先这个内存指的是虚拟内存。然后一般会回答主要有几个,当然除了这几个还有一些提的比较少的。而这些在/proc/pid/maps均能够看到:
    a. 堆区
    b. 栈区
    c. 数据段(静态、全局)
    d. 代码段(存放程序编译后的二进制代码)
    在这里插入图片描述
    /proc/pid/maps可以看到(在下面有解释):
root@swd-Lenovo-G40-80:/proc/4345# cat maps 
55d7d356d000-55d7d356e000 r-xp 00000000 08:02 17040544                   /home/swd/pros/c--learn/0.test_codes/demos/pmaps1
55d7d376d000-55d7d376e000 r--p 00000000 08:02 17040544                   /home/swd/pros/c--learn/0.test_codes/demos/pmaps1
55d7d376e000-55d7d376f000 rw-p 00001000 08:02 17040544                   /home/swd/pros/c--learn/0.test_codes/demos/pmaps1
55d7d404c000-55d7d406d000 rw-p 00000000 00:00 0                          [heap]
7f3f9f80f000-7f3f9f9f6000 r-xp 00000000 08:02 5505107                    /lib/x86_64-linux-gnu/libc-2.27.so
7f3f9f9f6000-7f3f9fbf6000 ---p 001e7000 08:02 5505107                    /lib/x86_64-linux-gnu/libc-2.27.so
7f3f9fbf6000-7f3f9fbfa000 r--p 001e7000 08:02 5505107                    /lib/x86_64-linux-gnu/libc-2.27.so
7f3f9fbfa000-7f3f9fbfc000 rw-p 001eb000 08:02 5505107                    /lib/x86_64-linux-gnu/libc-2.27.so
7f3f9fbfc000-7f3f9fc00000 rw-p 00000000 00:00 0 
7f3f9fc00000-7f3f9fc29000 r-xp 00000000 08:02 5505040                    /lib/x86_64-linux-gnu/ld-2.27.so
7f3f9fe12000-7f3f9fe14000 rw-p 00000000 00:00 0 
7f3f9fe29000-7f3f9fe2a000 r--p 00029000 08:02 5505040                    /lib/x86_64-linux-gnu/ld-2.27.so
7f3f9fe2a000-7f3f9fe2b000 rw-p 0002a000 08:02 5505040                    /lib/x86_64-linux-gnu/ld-2.27.so
7f3f9fe2b000-7f3f9fe2c000 rw-p 00000000 00:00 0 
7ffe5b0db000-7ffe5b0fc000 rw-p 00000000 00:00 0                          [stack]
7ffe5b125000-7ffe5b128000 r--p 00000000 00:00 0                          [vvar]
7ffe5b128000-7ffe5b12a000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
  • 这个是 64 位机器,所以地址会显得比较大
  • 每一列的含义:
第一列:本段在虚拟内存中的地址范围。
第二列:本段的权限。
第三列:偏移地址,即指本段映射地址在文件中的偏移。
第四列:主设备号与次设备号。
第五列:文件索引节点号。
第六列:映射的文件名。

a. 第一行: 权限是只读,并且可执行,是进程的代码段

55d7d356d000-55d7d356e000 r-xp 00000000 08:02 17040544                   /home/swd/pros/c--learn/0.test_codes/demos/pmaps1

b. 第三行:权限是可读可写,但是没有执行权限,是进程的数据段

55d7d376e000-55d7d376f000 rw-p 00001000 08:02 17040544                   /home/swd/pros/c--learn/0.test_codes/demos/pmaps1

c. 第四行:带有 [heap] 字样,说明是堆

55d7d404c000-55d7d406d000 rw-p 00000000 00:00 0                          [heap]

d. 倒数第四行:带有 [stack] 字样,说明是栈

7ffe5b0db000-7ffe5b0fc000 rw-p 00000000 00:00 0                          [stack]
  • 上面就说完了面试的内存布局了。那还剩下的是什么呢?
    i. ld-2.27共享库在 maps 的记录,每个共享库对应着3~4行,对应着数据段和代码段,主要是新的编译器对应的出来更加细分的段,有一些含义我也不清楚。
7f3f9f80f000-7f3f9f9f6000 r-xp 00000000 08:02 5505107                    /lib/x86_64-linux-gnu/libc-2.27.so
7f3f9f9f6000-7f3f9fbf6000 ---p 001e7000 08:02 5505107                    /lib/x86_64-linux-gnu/libc-2.27.so
7f3f9fbf6000-7f3f9fbfa000 r--p 001e7000 08:02 5505107                    /lib/x86_64-linux-gnu/libc-2.27.so
7f3f9fbfa000-7f3f9fbfc000 rw-p 001eb000 08:02 5505107                    /lib/x86_64-linux-gnu/libc-2.27.so
7f3f9fbfc000-7f3f9fc00000 rw-p 00000000 00:00 0
7f3f9fc00000-7f3f9fc29000 r-xp 00000000 08:02 5505040                    /lib/x86_64-linux-gnu/ld-2.27.so
7f3f9fe12000-7f3f9fe14000 rw-p 00000000 00:00 0 
7f3f9fe29000-7f3f9fe2a000 r--p 00029000 08:02 5505040                    /lib/x86_64-linux-gnu/ld-2.27.so
7f3f9fe2a000-7f3f9fe2b000 rw-p 0002a000 08:02 5505040                    /lib/x86_64-linux-gnu/ld-2.27.so

ii. 下面的段我现在也不认识

7ffe5b125000-7ffe5b128000 r--p 00000000 00:00 0                          [vvar]
7ffe5b128000-7ffe5b12a000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

好了,介绍完了这个 maps 的文件后,那这个文件有什么用呢?
作用可多了,对一些进程进行内存优化,先看这个文件:

  1. 先看堆区是否太大,在 malloc/new 的时候有没有开辟的太多内存
  2. 看栈区的大小,如果太大,看能不能合理调整结构体,栈变量有没有冗余。

看内存是否泄露:
3. 看进程的业务已经稳定了,观察堆区的大小是否在变大。变大就应该怀疑内存有泄露。

上面看地址的范围,很难计算出各个段占用内存的大小。那么还有一个文件可以看到占用的大小:

cat /proc/pid/smaps

4. 待定,这个/proc/pid 文件夹内还有很多有用的进程的信息,有空来补

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值