内存管理与分析

检测方法

如何定位分析程序中当前内存使用情况,可通过外部和内部两种方式来确定内存相关情况,

外部字段分析

只要知道进程的pid 即可通过命令 /proc/xxxx/satatus 来查看内存信息。其中xxxx为pid号.

显示的各个字段含义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
VmPeak: 代表当前进程运行过程中虚拟内存的峰值。
VmSize: 代表进程现在正在占用的虚拟内存。
VmLck: 代表进程已经锁住的物理内存的大小,锁住的物理内存不能交换到硬盘。
VmPin: 进程中被pin住的虚拟内存大小。
VmHWM: 进程得到分配的物理内存的峰值,应该是到目前为止的VmRSS的最大值。
VmRSS: 进程现在使用的物理内存。
RssAnon: 进程占用的物理内存中的匿名部分的大小,可以理解为RSS中除去RssFile和RssFile占用的部分。
RssFile: 进程占用的物理内存中用于文件映射的部分的大小。
RssShmem: 进程占用的物理内存中共享内存的部分的大小。
VmData: 表示进程虚拟内存中的数据段的大小。
VmStk: 表示进程虚拟内存中的堆栈段的大小。
VmExe: 表示进程虚拟内存中的代码段的大小
VmSwap: 进程占用Swap的大小。

内部定期输出

增加以下函数可以输出程序运行中当前内存的使用情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <malloc.h>   // mallinfo及malloc_stats依赖

static void display_mallinfo(int seq) {
struct mallinfo mi;
mi = mallinfo();
std::stringstream ss;

ss << "*************************** " << seq;
ss << "\nTotal non-mmapped bytes (arena): " << mi.arena;
ss << "\n# of free chunks (ordblks): " << mi.ordblks;
ss << "\n# of free fastbin blocks (smblks): " << mi.smblks;
ss << "\n# of mapped regions (hblks): " << mi.hblks;
ss << "\nBytes in mapped regions (hblkhd): " << mi.hblkhd;
ss << "\nMax. total allocated space (usmblks): " << mi.usmblks;
ss << "\nFree bytes held in fastbins (fsmblks): " << mi.fsmblks;
ss << "\nTotal allocated space (uordblks): " << mi.uordblks;
ss << "\nTotal free space (fordblks): " << mi.fordblks;
ss << "\nTopmost releasable block (keepcost): " << mi.keepcost;

fprintf(stderr, "--------------------stats info(%d)---------\n", seq);
malloc_stats();
fprintf(stderr, "%s\n", ss.str().c_str());
}

结果分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

--------------------stats info(0)---------
Arena 0: # 非mmap申请的内存区域 0
system bytes = 59752448 # glibc 向系统申请的内存大小, 单位字节
in use bytes = 27787856 # 用户进程通过 malloc 向 glibc 申请分配的内存大小
Arena 1: # 非mmap申请的内存区域 1
system bytes = 135168
in use bytes = 7504
Total (incl. mmap): # 所有内存信息(包含mmap),各个arena数值加上mmap信息
system bytes = 63369216 # 包含mmap的所有内存大小, 由mmap+各个Arena累计获取
in use bytes = 31276960 # 用户进程通过 malloc 向 glibc 申请分配的内存大小,由各个Arena累加获得
max mmap regions = 6 # mmap 区域个数
max mmap bytes = 3481600 # mmap 申请的内存字节数

*************************** 0
Total non-mmapped bytes (arena): 59887616 # 非mmap申请的内存字节数,等于stats info中所有的Arean的system bytes计数和(内存分配区域),包含正在使用的和空闲的
# of free chunks (ordblks): 12549 # 普通(即非fastbin)空闲块的数量
# of free fastbin blocks (smblks): 6 # fastbin空闲块的数量
# of mapped regions (hblks): 6 # 当前使用mmap分配的块数
Bytes in mapped regions (hblkhd): 3481600 # 当前使用mmap分配的块中的字节数
Max. total allocated space (usmblks): 0 # 该字段未使用,始终为0。以前代表已分配最大空间(以字节为单位)。
Free bytes held in fastbins (fsmblks): 592 # fastbin空闲块中的字节总数
Total allocated space (uordblks): 27794800 # 使用中的分配所使用的字节总数
Total free space (fordblks): 32092816 # 空闲块中的字节总数
Topmost releasable block (keepcost): 4016 # 堆顶部的可释放可用空间总量。这是malloc_trim理想情况下可以释放的最大字节数(即:忽略页面对齐限制等)

参考

1
2
3
4
5
6
7
8
https://man7.org/linux/man-pages/man3/mallinfo.3.html
https://www.onitroad.com/jc/linux/man-pages/linux/man3/mallinfo.3.html
https://www.cnblogs.com/dongzhiquan/p/5621906.html
https://www.onitroad.com/jc/linux/man-pages/linux/man3/malloc_trim.3.html
http://www.xtaohub.com/System-Microscope/how-to-use-memory.html
https://wenfh2020.com/2021/04/08/glibc-memory-leak/
https://blog.csdn.net/weixin_39636610/article/details/113053005
https://www.modb.pro/db/237286