前言:
procrank是一个统计内存使用的神器,包括VSS,PSS,PSS和USS的详细参数。作为一个内存使用的分析工具,简直厉害的不要不要的。
作者尝试过几个Linux发行版,都没有把procrank作为可以安装的包。这也不奇怪,作者接触这个命令的时候,也是在Android中使用到的。尽管后来不从事嵌入式开发了,每当遇到类似的问题时,都会情不自禁的想到这个神奇的工具。在Iaas平台中,统计KSM也是利器。
源代码:
如上面所说,代码选自Android的源代码。为了使用方便,作者在github上做了一份拷贝,并写了一个简单的Makefile,方便安装使用。特此声明。
代码见:https://github.com/pacepi/procrank
分析:
1,在分析procrank的代码之前,需要先了解到/proc/pid/pagemap这个文件。
代码实现在linux-4.0.4/fs/proc/task_mmu.c文件的pagemap_read函数中。
哪怕不阅读代码,只看注释,也可以大概了解到:通过/proc/pid/pagemap可以遍历得到当前进程的所有物理页面的PFN和另外的几个标志位。
2,了解/proc/kpagecount文件。
代码实现在linux-4.0.4/fs/proc/page.c文件的kpagecount_read函数中。
依然只看注释,也大致了解到:通过传进来的PFN来计算当前的page被映射过几次。
3,了解/proc/kpageflags文件。
代码实现在linux-4.0.4/fs/proc/page.c文件的kpageflags_read函数中。函数实现了通过PFN获取page的flags的功能。
4,了解/proc/pid/maps文件。
代码实现在linux-4.0.4/fs/proc/task_mmu.c文件的show_map_vma函数中。如图,就是cat命令的maps。maps中描述了进程的虚拟内存空间的分布情况,即一段一段的连续地址区间,所有区间大小的和就是VSS。这就是传说中的“虚拟内存空间”。关于maps,后面会在使用maps解决进程crash的时候详细说明。
5,进入正题,开始分析procrank。
a,既然要分析所有的进程的内存使用情况,那么就需要遍历/proc目录下所有的数字目录,数字就是系统的所有的进程的pid(top,ps等命令,都如此)。
对于每一个进程:
b,打开pagemap,并通过maps获取到所有的map区间。
c,遍历待统计的进程的maps中的所有地址区间,通过pagemap得到进程使用的所有的PFN。再通过kpagecount&kpageflags得到所有的PFN被引用的次数和对应的flags。
d,如上图(例子中pagesize按4k计算),开始计算:
RSS:只要页面在自己的区间内被映射过,就算在自己的头上。例如/lib/x86_64-linux-gnu/libc-2.23.so的某一个页面被60个进程使用过,那么自己还是要算上4K。
PSS:页面被多个进程映射过,那么把使用量平均到大家头上。那么libc的这个页面就只能算在自己头上4k / 60 = 68Bytes。
USS:页面只有被自己使用过,才算到自己头上。USS的统计意义在于,如果这个进程被杀掉了,那么实际上只能释放这么多内存。
e,分析过后,很容易得出结论,一般情况下,都是:VSS >= RSS >= PSS >= USS。分析到此结束。
后记:
一朋友是数据库高手,redis,sql,mongodb都玩的溜。和作者小小抱怨了一下:数据库一般占用内存偏多,但是只要系统内存偏高,哪怕不是db引起的,依然会被找麻烦。于是作者告诉他了这个利器,“怼”回去!!!!
效果图~