grep命令详解_给进程排个队 - Linux中ps命令的使用

40039ff5cc1b126fb78d4d654103832f.png

在Linux中,ps命令是很常用的,可是这个命令虽然看起来简单,但往往需要配合各种参数才能得到有用的信息,而ps的参数系统可以说是混乱至极,它要称自己第二,估计没有其他的命令敢称第一。首先,很多参数的效果是差不多的,有相当多重叠的部分,再次,很多参数是不能配合在一起使用的。

造成这种混乱很大的原因是现在Linux主流发行版的ps命令是同时兼容System V和BSD的,关于这一块的详细分析请看史上最全 Linux ps 命令详解这篇文章,一般我看到什么“史上最全”之类的标题都会嗤之以鼻,但这篇文章,可能真的是国内讲解ps命令最全的文章了。

作为运维工程师,需要对ps命令掌握的更全面一些,但是作为开发工程师,在这个命令的使用过程中,侧重点可能会稍有不同。因此本文主要是结合开发的实际需要,从中提取总结了一些比较实用的参数,并结合procrank工具和top命令,进行了一定程度的扩展。

进程占用内存

在讲解ps命令的参数之前,有必要先介绍一下Linux对进程占用内存的计算依据。因为Linux中的进程是使用虚拟地址的,这些进程通过malloc()或者mmap()向内存申请内存之后(这部分内存大小称为VSS - Virtual Set Size),内核并不会立刻为其分配实际的物理内存。等到进程真正使用到内存时(比如调用了memset()函数),内核才会为这个进程分配物理内存,并建立虚拟地址和物理地址之间的映射(参考这篇文章)。

计算这段分配的物理内存的大小并不难,可是Linux中的进程是广泛使用共享的动态链接库的(后缀名为so - shared object),而动态链接库本身也是要占据物理内存的,那这部分内存应该算在哪个进程头上呢?

为此就出现了三种不同的计算方法(统计口径),一种是只计算进程自身占用的物理内存,完全不包含共享库所占用内存的USS(Unique Set Size),一种是把共享库占用的内存直接加到每个进程头上的RSS(Resident Set Size)。

USS和RSS的统计方法虽然简单,但显得不是那么合理,更公平一点的做法是把一个共享库占用的内存,分摊到使用了这个共享库的各个进程头上,称为PSS(Proportional Set Size),类似于小区里面的“公摊面积”。

f70aaa3134505dcc8d3ff47be700b909.png

之所以说“类似”,是因为两者还是存在一定的区别,公摊面积通常是按照房屋的实际大小乘以一个百分比获得,也就是说房屋面积越大,公摊面积也越大,而PSS虽然是叫"Proportional",但这名字其实是具有误导性的,它实际的做法是平分。比如一个共享库占用了3MiB的物理内存,有3个进程使用了这个库,那么摊派到每个进程头上的都是1MiB。房屋建好后大小就固定了,但进程自身占用的内存是动态变化的,按比例分摊就太麻烦了。

假设现在这3个进程中有一个被kill掉了,那么共享库这3MiB的内存就要分摊到另外2个还存活的进程上,此时这个被kill的进程所释放的内存大小就不是它的PSS,而是它的USS。

ps命令的参数

介绍完了进程占用内存的计算依据,接下来就可以结合各个参数,来查看ps命令输出的各种信息了。要显示所有的用户进程和内核线程,加上参数"-e"即可:

caaafaa2ab5000ce36e257bf346c06d9.png

如果只想查看用户进程,则加上参数"u"或"l"。"u"和"l"都可以显示VSZ(即VSS),RSS和执行时间统计,此外"u"还可以显示CPU和memory占用率:

ccc2e36fd9b788893c6d028e72c23e93.png

而"l"可以显示优先级、nice值和PPID:

ffb56d3a2f16ad2bc6807d2cc803f4cc.png

单独使用"-e"虽然可以查看所有进程/线程,但关于每个进程/线程的信息有限,而且甚至都无法分别其中的一项到底是用户进程还是内核线程,因此"-e"参数通常应该配合"u"或"l"使用:

140eb98ac3ec42c04d64056825237131.png

用"[]"包起来的就是内核线程,我们可以利用这一特性来实现只查看内核线程,像这样:

ps -e u | grep '[.*]'

内核线程所占用的内存大小不通过VSZ和RSS表达,所以在ps命令的输出中,内核线程对应的VSZ和RSS的值都为0。

由于用户进程之间存在继承关系,可以通过加"f"参数来查看这种关系,输出结果以树形排列的形式呈现:

5f57e515fc6dbdcfc39412f6fe8c0c45.png

单独使用"f"跟单独使用"-e"一样,得到的关于每一个进程/线程的信息有限,而"f"也同"-e"一样,可以联合"u"或"l"使用以获得更全面的进程信息。

既然"u"和"l"可以显示进程中各个特性的详细信息,那我们肯定希望必要的时候,可以按照其中的某个特性来排序,比如按RSS排序以查看哪个进程消耗的内存最大(虽然并不是那么准确,但还是可以看个大概嘛),这就要用到"k"参数。

"k"后面跟上某个特性的名称,就可以按照这个特性排序,例如"k rss"即是按rss升序,"k -rss"则是按rss降序,其他常用的包括按CPU占用率排序的"%cpu",按执行时间排序的"time"等。因为有些进程在启动时的名称很长(比如qemu),可以再加上一个"c",让输出排列的比较整齐。

4a429618e708d48dc9c4a4b30a09a230.png

在多核系统中,有时我们可能还有兴趣看看这个进程/线程现在是哪个核上运行啊,"-P"参数可以帮助我们查看这个信息。此外,一个用户进程往往是由多个线程组成的,可以通过加上"-L"参数来显示线程。

如果我们把"-P"和"-L"结合起来查看启动QEMU虚拟机的"qemu-system-aarch64"进程的线程运行情况,可以看到它一共包含6个线程。

947f5df02c332cd952e24346d9c62891.png

在启动这个QEMU虚拟机时,我使用的是"-smp 4",也就是4个CPU, 我们可以进入QEMU的命令行模式(通过"ctrl-a + c"),输入"info cpus"来查看这4个CPU的信息。

e6792b881f8482d87899c6482f5b7e1d.png

可以看到,这4个CPU使用了4个线程,而这4个线程的PID就是包含在我们之前用ps命令看到的6个线程中的,而且这4个线程是运行在同一个CPU上。QEMU中guest使用的是虚拟CPU,每个虚拟CPU由host的一个线程来模拟,这4个虚拟CPU共享一个host上的一个物理CPU。

procrank工具

在Android上面做过开发的同学可能知道,Android提供一个procrank工具,可以很方便的查看各进程的内存使用情况,排序依据可以是VSS, RSS, PSS或者USS。

而我们完全可以把procrank工具移植到Linux系统上来,只需下载这个repo,根据自己运行Linux的架构,交叉编译一下就可以了。

d7dbc5de77de0259df80268f9f1bb646.png

其实啊,如果你理解了ps命令的那些参数,虽然略微繁琐了点,但完全可以实现和procrank类似的输出,虽然不像procrank那么完备,可以一并显示VSS, RSS, PSS和USS的信息,但作为初步调试基本够用了。毕竟,当你遇到一台出现问题的Linux机器需要调试时,那台机器上大多没有安装procrank,有时临时移植一个也不现实,而用ps命令加参数的方式就可以不受这种限制。

4e0d9bf8e301bb816baee6e0b76a7742.png

top命令

Linux中另一个常用的命令是top,它通常用于查看CPU的占用率,但同时也能显示VSS和RSS的信息,只不过在这里叫法不一样,分别被称为了"VIRT"和"RES"。top命令的输出默认是按CPU占用率排序的,但同样可以实现按照其他规则排序,比如在top命令的运行过程中,使用"shift+m"就是按RES/内存排序,使用"shift+t"就是按CPU执行时间排序,"shift+p"则可切回按照CPU占用率排序。

c25c08838939c3e898c521e32cad1324.png

看来ps命令和top命令的输出也很多重叠的部分(毕竟它们都是从"/proc/$(pidof process)/stat"里提取的信息),也许两者最大的区别就是top命令可以一直动态刷新显示。好处当然是可以实时观察变化,但之前的数据会被新的数据覆盖掉。其实用ps指令配合很简单的shell脚本,像这样

while true; do ps; sleep 3; done

也可以实现实时地输出数据:

5e38a7de5b1b0b0dfc3ea1766dd913b8.png

参考:

Proportional set size

Android_Memory_Usage

http://jackjia.cc/linux-command-top

原创文章,转载请注明出处。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值