zoukankan      html  css  js  c++  java
  • 剖析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的物理内存。

     
     
  • 相关阅读:
    Brain network involved in autonomic functions 与自主功能相关的大脑网络
    Brief summary of classical components of ERP 事件相关成分(ERP)经典成分小结
    ICA & Percentage Variance Account For (PVAF)
    数据处理中白化Whitening的作用图解分析
    Loadings vs eigenvectors in PCA 主成分分析(PCA)中的负荷和特征向量
    主成分分析(PCA)和独立成分分析(ICA)相关资料
    Sketch of heart and QRS complex 心脏及QRS波群简图
    Brain Network visulation in EEG 脑电网络可视化
    Phase Locking Value (PLV) 神经信号的锁相值
    ubuntu16.04下的一些基本操作笔记
  • 原文地址:https://www.cnblogs.com/williamjie/p/9297998.html
Copyright © 2011-2022 走看看