做人呢,最紧要就系开心啦

Linux内核之内存3: 进程的内存消耗和内存泄漏

988次阅读
没有评论

1. 进程的 VMA

(1) 进程地址空间

在 Linux 系统中,每个进程都有自己的虚拟内存空间 0~3G;

内核空间只有一个 3G~4G;

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

进程通过系统 API 调用,在内核空间申请内存,不统计在任何用户进程;进程消耗内存,单指用户空间内存消耗;

(2)VMA 列表

LINUX 用 task_struct 来描述进程,其中的 mm_struct 是描述内存的结构体,mm_struct 有一个 vma 列表,管理当前进程的所有 vma 段。

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

每个进程的内存由多个 vma 段组成:

(3) 查看 VMA 方法:

1.pmap

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

由图知,从接近 0 地址开始,第一个 4K 是只读代码段,第二个 4K 是只读数据段,还有其他共享库代码段,堆栈等;

可见一个进程的 VMA 涵盖多个地址区域 ,但并没有覆盖所有地址空间 。VMA 未覆盖的地址空间是 illegal 的,访问这些地址,缺页中断,发生 pagefault.

2.cat /proc/pid/maps

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

读文件形式,与 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 的三个方法对比

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

VMA 的来源,代码段,数据段,堆栈段。

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

VMA 是 linux 最核心数据结构之一。

2.page fault 的几种可能性,major 和 minor

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

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。

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

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

Linux 内核之内存 3: 进程的内存消耗和内存泄漏


./a.out &
pidof a.out

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

cat /proc/pid_2/smaps |more

PSS 变化

shared_clean

private_clean

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

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

统计系统的内存消耗,查看 PSS。

检查有没有内存泄漏,检查 USS

./smem

smem –pie=command

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

smem –bar=command

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

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

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

==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)

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

valgrid 是在虚拟机跑 APP,速度很慢;

新版 gcc4.9 以后集成了 asan

asan:

    gcc -g -fsanitize=address ./leak-example.c

    gcc -fuse-ld=gold -fsanitize=address -g ./lsan.c

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

#1 0x40084e in main lsan.c:9

内存泄漏不一定在用户空间,排查内核空间,检测 slab , vmalloc

slaptop, 检查申请和释放不成对。

在内核编译,打开 kmemleak 选项。

5. 工程调试内存泄漏问题一般步骤:

(1) meminfo, free 多点采样确认有内存泄漏。

(2) 定位,smem 检查用户空间

Linux 内核之内存 3: 进程的内存消耗和内存泄漏

USS 在不断增加。

(3) slab, 检查内核空间。

cat /proc/slabinfo

其他查看内存信息的方法

cat /proc/meminfo

cat /proc/buddyinfo

cat /proc/zoneinfo

cat /proc/meminfo

正文完
 1
admin
版权声明:本站原创文章,由 admin 2022-01-04发表,共计2604字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)