1.进程的VMA
(1)进程地址空间
在Linux系统中,每个进程都有自己的虚拟内存空间0~3G;
内核空间只有一个3G~4G;
进程通过系统API调用,在内核空间申请内存,不统计在任何用户进程;进程消耗内存,单指用户空间内存消耗;
(2)VMA列表
LINUX用task_struct来描述进程,其中的mm_struct是描述内存的结构体,mm_struct有一个vma列表,管理当前进程的所有vma段。
每个进程的内存由多个vma段组成:
(3)查看VMA方法:
1.pmap
由图知,从接近0地址开始,第一个4K是只读代码段,第二个4K是只读数据段,还有其他共享库代码段,堆栈等;
可见一个进程的VMA涵盖多个地址区域,但并没有覆盖所有地址空间。VMA未覆盖的地址空间是illegal的,访问这些地址,缺页中断,发生pagefault.
2.cat /proc/pid/maps
读文件形式,与pmap一一对应;
3.cat /proc/pid/smaps
更详细的描述
00400000-00401000 r-xp 00000000 08:15 20316320 /home/leon/work/linux/mm/a.out
Size: 4 kb
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 4 kB
Private_Dirty: 0 kB
Referenced: 4 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
VmFlags: rd ex mr mw me dw sd
查看VMA的三个方法对比
VMA的来源,代码段,数据段,堆栈段。
VMA是linux最核心数据结构之一。
2.page fault的几种可能性,major和minor
mmu给cpu发page fault时,可以从寄存器读到两个元素,pagefault地址,pagefault原因。
(1)访问Heap堆(首次申请,不是从Libc获取),第一次写,发生pagefault,linux检查VMA权限,发现权限合法,发缺页中断,申请一页内存,并更新页表。
(2)访问空区域,访问非法,发段错误;
(3)访问代码段, 在此区域写,报pagefault,检查权限发现错误,报段错误;
(4)访问代码段,在此区域读/执行,linux检查权限合法,若代码不在内存,那么申请内存页,把代码从硬盘读到内存。
伴随I/O的pagefault, 叫major pagefault, 否则minor pagefault.
major pagefault耗时远大于 minor pagefault.
\time -v python hello.py
3.内存是如何被瓜分的: :vss、rss、pss和uss
rss是不是代表进程的内存消耗呢,NO。
VSS:单个进程全部可访问的地址空间,但未必所有虚拟地址都已经映射物理内存;
RSS:驻留内存,单个进程实际占用的物理内存大小(不十分准确的描述);上图的进程1
PSS:
比例化的内存消耗,相对RSS,将共享内存空间按被共享进程数量比例化;上图的C库4被三个进程共享,所以4/3;
USS:进程独占内存,比如上图的堆6。
案例,连续运行两次a.out,查看内存占用情况
运行程序a.out
./a.out &
pidof a.out
cat /proc/pid/smaps |more
./a.out &
pidof a.out
cat /proc/pid_2/smaps |more
PSS变化
shared_clean
private_clean
4.应用内存泄漏的界定方法
统计系统的内存消耗,查看PSS。
检查有没有内存泄漏,检查USS
./smem
smem –pie=command
smem –bar=command
android里面有类似的工具,procmem/procrank
smem分析系统内存使用是通过/proc/smaps的,procrank是通过分析/proc/kpagemap。
5.应用内存泄漏的检测方法:valgrind和addresssanitizer
其他查询内存泄漏工具:
valgrind:
gcc -g leak-example.c -o leak-example
valgrind --tool=memcheck --leak-check=yes ./leak-example
==20468== HEAP SUMMARY:
==20468== in use at exit: 270,336 bytes in 22 blocks
==20468== total heap usage: 44 allocs, 22 frees, 292,864 bytes allocated
==20468==
==20468== 258,048 bytes in 21 blocks are definitely lost in loss record 2 of 2
==20468== at 0x4C2DB8F: malloc (in
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20468== by 0x4005C7: main (leak-example.c:6)
valgrid是在虚拟机跑APP,速度很慢;
新版gcc4.9以后集成了asan
asan:
gcc -g -fsanitize=address ./leak-example.c
gcc -fuse-ld=gold -fsanitize=address -g ./lsan.c
#1 0x40084e in main lsan.c:9
内存泄漏不一定在用户空间,排查内核空间,检测slab , vmalloc
slaptop, 检查申请和释放不成对。
在内核编译,打开kmemleak选项。
5.工程调试内存泄漏问题一般步骤:
(1) meminfo, free 多点采样确认有内存泄漏。
(2)定位,smem检查用户空间
USS在不断增加。
(3) slab,检查内核空间。
cat /proc/slabinfo
其他查看内存信息的方法
cat /proc/meminfo
cat /proc/buddyinfo
cat /proc/zoneinfo
cat /proc/meminfo