郝健: Linux内存管理学习笔记-第3节课

640?wx_fmt=png&wxfrom=5&wx_lazy=1

摘要

进程的虚拟地址空间VMA(Virtual Memory Area)

Pagefault的几种可能性、VMA的作用、major缺页和minor缺页

进程内存消耗的4个概念:vss、rss、pss和uss

应用内存泄漏的界定方法

内存泄漏的检测工具:valgrind和addresssanitizer

 

 

1.    进程的虚拟地址空间VMA(Virtual Memory Area)

640?wx_fmt=png

上图中,task_struct中的mm_struct就代表进程的整个内存资源,mm_struct中的pgd为页表,mmap指针指向的vm_area_struct链表的每一个节点就代表进程的一个虚拟地址空间,即一个VMA。一个VMA最终可能对应ELF可执行程序的数据段、代码段、堆、栈、或者动态链接库的某个部分。

 

VMA的分布情况可以有通过pmap命令,及maps,smaps文件查看,如下图:

640?wx_fmt=png

pmap pid

pmap – report memory map of a process

 

/proc/<pid>/maps及/proc/<pid>/smaps更详细展示了进程VMA的分布情况。

 

观察pmap结果及maps,smaps文件,可以发现注:IA32下,一个进程的VMA是在0~3G之间分散分布的,是一段一段的,中间会有很多空白区域,空白区域对进程来说都是不能访问的,VMA中会标注这一段的RWX的具体权限。如下图所示:

640?wx_fmt=png

另,VMA的具体内容可参考下图。

640?wx_fmt=png

2.    Page fault的几种可能性、VMA的作用、major缺页和minor缺页

640?wx_fmt=png

1)如,调用malloc申请100M内存,IA32下在0~3G虚拟地址中立刻就会占用到大小为100M的VMA,且符合堆的定义,这一段VMA的权限是R+W的。但由于Lazy机制,这100M其实并没有获得,这100M全部映射到一个物理地址相同的零页,且在页表中记录的权限为只读的。当100M中任何一页发生写操作时,MMU会给CPU发page fault(MMU可以从寄存器读出发生page fault的地址;MMU可以读出发生page fault的原因),Linux内核收到缺页中断,在缺页中断的处理程序中读出虚拟地址和原因,去VMA中查,发现是用户程序在写malloc的合法区域且有写权限,Linux内核就真正的申请内存,页表中对应一页的权限也修改为R+W。

2)如,程序中有野指针飞到了此程序运行时进程的VMA以外的非法区域,硬件就会收到page fault,进程会收到SIGSEGV信号报段错误并终止。

3)如,代码段在VMA中权限为R+X,如果程序中有野指针飞到此区域去写,则也会发生段错误。(另,malloc堆区在VMA中权限为R+W,如果程序的PC指针飞到此区域去执行,同样发生段错误。)

4)如,执行代码段时会发生缺页,Linux申请1页内存,并从硬盘读取出代码段,此时产生了IO操作,为major主缺页。

640?wx_fmt=png

综上,page fault后,Linux会查VMA,也会比对VMA中和页表中的权限,体现出VMA的重要作用。

 

3.    进程内存消耗的4个概念:vss、rss、pss和uss

首先,我们评估一个进程的内存消耗都是指用户空间的内存,不包括内核空间的内存消耗,即IA32下,虚拟地址在0~3G的部分所对应的物理地址的内存。

VSS – Virtual Set Size

RSS – Resident Set Size

PSS – Proportional Set Size

USS – Unique Set Size

640?wx_fmt=png

1044,1045,1054三个进程,每个进程都有一个页表,对应其虚拟地址如何向real memory上去转换。

process 1044的1,2,3都在虚拟地址空间,所以其VSS=1+2+3。

process 1044的4,5,6都在real memory上,所以其RSS=4+5+6。

 

分析real memory的具体瓜分情况:

4  libc代码段,1044,1045,1054三个进程都使用了libc的代码段,被三个进程分享。

5  bash shell的代码段,1044,1045都是bash shell,被两个进程分享。

6  1044独占

所以,上图中4+5+6并不全是1044进程消耗的内存,因为4明显被3个进程指向,5明显被2个进程指向,衍生出了PSS(按比例计算的驻留内存)的概念。进程1044的PSS为4/3 +5/2 +6。

最后,进程1044独占且驻留的内存USS为 6。

 

一般情况下,VSS >= RSS >= PSS >= USS。

 

评估进程内存耗费情况一般使用smem工具,查看PSS(最公平):

1)命令行模式

640?wx_fmt=png

2)饼状图模式

640?wx_fmt=png

3)柱状图模式

640?wx_fmt=png

跑一个死循环程序,观察其smaps文件。然后再把此程序跑一份,观察其smaps文件变化(smaps内容很长,只看第一段):

640?wx_fmt=png

可以看出PSS由4k变为2k,而Shared_clean由0k变为4k,Private_clean由4k变为0k。

 

4.    应用内存泄漏的界定方法

内存泄漏:进程运行的时间越久,耗费的内存越多,申请与释放不成对。

内存泄漏只看USS即可。

观察内存泄漏使用连续多点采样法:

640?wx_fmt=png

 

5.    内存泄漏的检测工具:valgrind和addresssanitizer

640?wx_fmt=png

每次free(p2),没有free(p1),申请与释放不成对。

 

使用valgrind检测由内存泄漏的程序:

640?wx_fmt=png

使用addresssanitizer中的lsan工具检测程序内存泄漏:

640?wx_fmt=png

调用 __lsan_do_leak_check()做检查

640?wx_fmt=png

检测出泄漏了10次。

640?wx_fmt=png

如今更流行使用addresssanitizer。


内存管理报名

报名:《Linux的任督二脉》之《内存管理》微课(连续5晚)

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注