剖析top命令显示的VIRT RES SHR值

http://yalung929.blog.163.com/blog/static/203898225201212981731971/ 

http://www.fuzhijie.me/?p=741 

 

引 言: top命令作为Linux下最常用的性能分析工具之一,可以监控、收集进程的CPU、IO、内存使用情况。比如我们可以通过top命令获得一个进程使用了多少虚拟内存(VIRT)、物理内存(RES)、共享内存(SHR)。

最近遇到一个咨询问题,某产品做性能分析需要获取进程占用物理内存的实际大小(不包括和其他进程共享的部分),看似很简单的问题,但经过研究分析后,发现背后有很多故事……

1 VIRT RES SHR的准确含义

 

剖析top命令显示的VIRT RES SHR值 - yalung - Y A L U N G

 

三个内存指标,VRIT,RES,SHR准确含义是什么?谁能告诉我们?MAN页?Linux专家?SUSE工程师?Linus?谁能说出最正确答案?没人!因为惟有源代码才是最正确的答案。

那我们就去看下源码吧,这就是开源软件的最大的好处。

首先这三个数据的源头,肯定是内核,进程的相关数据结构肯定是由内核维护。那么top作为一个用户空间的程序,要想获取内核空间的数据,就需要通过系统接口(API)获取。而proc文件系统是Linux内核空间和用户空间交换数据的一个途径,而且是非常重要的一种途径,这点和windows更倾向于基于函数调用的形式不同。

当你调用系统函数read读取一个普通文件时,内核执行对应文件系统的代码从磁盘传送文件内容给你。

当你调用系统函数read读取一个 proc文件时,内核执行对应的proc文件系统的代码从内核的数据结构中传送相关内容给你。proc文件和磁盘没有关系。只是系统接口而已。

而一个进程的相关信息,Linux全部通过/proc/<pid>/内的文件告诉了我们。

如下,你可以使用普通的文件读写工具,比如cat获取进程的各种信息。这比函数调用的方式灵活多了、丰富多了。

 

剖析top命令显示的VIRT RES SHR值 - yalung - Y A L U N G

 

 

回到我们的问题,top命令显示的进程信息,肯定也是通过proc获取的,因为除此之外没有其他途径,没有系统函数可以做这个事情,top也不可能越过用户层直取内核获取数据。

带着以上信息,很快就可以从top的源码中找到关键代码:

 

剖析top命令显示的VIRT RES SHR值 - yalung - Y A L U N G

  

啊哈,statm文件:

 

剖析top命令显示的VIRT RES SHR值 - yalung - Y A L U N G

 

根据sscanf的顺序,第一个值是VIRT,第二个值是RES,第三个值是SHR!

等等,好像数值对不上,top显示的SHR是344k,而statm给出的是86!

再来看一行关键代码:

 

剖析top命令显示的VIRT RES SHR值 - yalung - Y A L U N G

  

statm显示的是页数,top显示的是KB。X86下,一页是4KB,86 * 4 = 344。这就对了!

 

于是乎,我们找到了最关键的入口,接下来按图索骥,看看内核是怎么产生statm文件内容就可以了。~~

 

剖析top命令显示的VIRT RES SHR值 - yalung - Y A L U N G

 

 

proc_pid_statm函数负责产生statm文件内容,当你使用cat命令打印statm文件时,内核中的这个函数会执行。

proc_pid_statm获取进程的mm_struct数据结构,而这个数据结构就是进程的内存描述符,通过它可以获取进程内存使用、映射的全部信息。

     进一步考察task_statm函数,可以看到:

 

剖析top命令显示的VIRT RES SHR值 - yalung - Y A L U N G

 

第一个值(VIRT)就是mm->total_vm,即进程虚存的总大小,这个比较清晰,只要进程申请了内存,无论是malloc还是堆栈还是全局,都会计入这个值;

第二个值(RES)是mm->file_rss+mm->anon_rss;

第三个值(SHR)是mm->file_rss。

 RES要和SHR结合者看,内核把物理内存分为了两部分,一部分是映射至文件的,一部分是没有映射至文件的即匿名内存,完全和共不共享没有关系!

但file_rss为什么叫做shared呢?应该是一种指示性表述,表示这部分内存可能是共享的。但并不代表真正共享了。那么到底哪些计入file_rss?通过查阅相关代码,发现(可能有遗漏):

l 程序的代码段。

l 动态库的代码段。

l 通过mmap做的文件映射。

l 通过mmap做的匿名映射,但指明了MAP_SHARED属性。

l 通过shmget申请的共享内存。

 即进程通过以上方式占用的物理内存,计入file_rss,也就是top的SHR字段。我们看到一般这些内存都是以共享方式存在。但如果某个动态库只一个进程在使用,它的代码段就没有被共享着。

反过来再来看anon_rss统计的内容,是否就一定是独占的?也不是,比如新fork之后的子进程,由于copy on write机制,在页面被修改之前,和父进程共享。这部分值并不体现在top命令的SHR字段内。

 综上所述top命令显示的SHR字段,并不是准确描述了进程与其他进程共享使用的内存数量,是存在误差的。 

那么如何获取进程准确的共享内存数量?

2 获取进程准确的共享内存数量

我们注意到在描述进程信息的proc/<pid>内,有一个smaps文件,里面展示了所有内存段的信息,其中有Shared_Clean Shared_Dirty Private_Clean Private_Dirty:几个字段。

 

剖析top命令显示的VIRT RES SHR值 - yalung - Y A L U N G

  

 

找到相关代码,可以看到,一个页面如果映射数>=2计入Shared_* ; 如果=1计入Private_*。(脏页计入*_Dirty,否则计入*_Clean)

 

 

剖析top命令显示的VIRT RES SHR值 - yalung - Y A L U N G

 

     统计smaps文件内所有段的Shared_*值的总和就是进程准确的共享内存数量!

     统计smaps文件内所有段的Private_*值的总和就是进程准确的独占内存数量!

3 总结

通过以上分析,我们可以得到如下结论:

l top命令通过解析/proc/<pid>/statm统计VIRT和RES和SHR字段值。

l VIRT是申请的虚拟内存总量。

l RES是进程使用的物理内存总和。

l SHR是RES中”映射至文件”的物理内存总和。包括:

程序的代码段。

动态库的代码段。

通过mmap做的文件映射。

通过mmap做的匿名映射,但指明了MAP_SHARED属性。

通过shmget申请的共享内存。

l /proc/<pid>/smaps内Shared_*统计的是RES中映射数量>=2的物理内存。

l /proc/<pid>/smaps内Private_*统计的是RES中映射数量=1的物理内存。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: VIRT: 表示进程使用的虚拟内存大小,包括共享库占用的内存。 RES: 表示进程使用的物理内存大小。 SHR: 表示进程与其他进程共享的内存大小。 %CPU: 表示进程使用的 CPU 时间的百分比。 ### 回答2: 在Linux下,top命令能够实时显示系统的进程和资源使用情况。下面是对top命令下的VIRT、RES、SHR、S和%CPU的含义解释: 1. VIRT:表示进程所使用的虚拟内存大小。虚拟内存是计算机在硬盘上模拟出来的一块内存空间,用于存储进程的代码、数据和堆栈等。VIRT的数往往比实际物理内存大小要大,因为它包含了共享库、映射文件和堆栈等。 2. RES:表示进程实际使用的物理内存大小。物理内存是计算机实际可用的内存空间,它用于存储进程当前运行所需要的数据和指令。RES的数反映了进程实际占用的物理内存大小。 3. SHR:表示进程所使用的共享内存大小。共享内存是一种特殊的内存区域,它可以同时被多个进程访问,用于减少内存使用,提高系统效率。SHR的数可以反映出进程共享内存的大小。 4. S:表示进程的状态。常见的状态有R(运行)、S(睡眠)、D(不可中断的睡眠)、Z(僵死)等。S列可以用来查看进程当前的状态信息。 5. %CPU:表示进程当前的CPU使用率。它是指进程占用CPU时间片的百分比,数越高表示进程使用的CPU资源越多。 通过查看这些指标,可以帮助我们更好地了解系统的进程和资源使用情况,并且有助于进行系统性能分析和优化。 ### 回答3: 在Linux下,top命令显示了当前进程的一些重要信息。下面分别解释一下其中的VIRT、RES、SHR、S和%CPU的含义: 1. VIRTVirtual Memory):虚拟内存VIRT代表进程所占用的虚拟内存空间的大小。它包括程序、库文件、堆空间和栈空间等。但是,并非所有的虚拟内存都被进程实际使用,因为其中的一部分可能是共享的或者是由动态链接库所占用的。 2. RES(Resident Set Size):驻留内存。RES代表进程实际使用的物理内存大小。它表示进程当前实际占用的物理内存空间,包括进程使用的堆内存、栈内存和共享库等。RES是通过读写页表来计算的。 3. SHR(Shared Memory):共享内存SHR代表进程所使用的共享内存大小。共享内存是指多个进程可以同时访问的内存空间。多个进程可以共享某些相同的库文件、数据区域等。SHRVIRT中共享部分的子集,因此它是VIRT减去RES的结果。共享内存对于减少内存的占用是非常有帮助的。 4. S(Status):进程状态。S代表进程的当前状态,例如运行(R)、等待(S)、停止(T)或僵死(Z)等。进程状态可以帮助我们了解进程的执行状态,以及进程是否正常运行或出现异常。 5. %CPU(CPU Usage):CPU使用率。%CPU代表进程的CPU利用率。它是指进程在一段时间内使用CPU的时间片比例。它可以帮助我们判断哪些进程占用了大量的CPU资源,以便优化系统的性能。 总结起来,VIRT表示进程的虚拟内存大小,RES表示进程的物理内存大小,SHR表示进程的共享内存大小,S表示进程的状态,%CPU表示进程的CPU利用率。这些信息能够帮助我们了解进程的内存占用和运行状态,以便进行性能分析和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值