定位进程占用内存问题

定位一个服务内存占用率过高的问题:

起因

机器报警,内存不足,用free命令去看,看到内存不足
用top 然后M按内存使用率排序,找到服务的进程号
top -p 进程号
看到这个进程占用了1.5G的虚拟内存

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat /proc/<pidnum>/status
......
Groups: 0 1 2 3 4 6 10
VmPeak: 1614960 kB
VmSize: 1549424 kB
VmLck: 12 kB
VmPin: 0 kB
VmHWM: 65352 kB
VmRSS: 33520 kB
VmData: 1046480 kB
VmStk: 688 kB
VmExe: 640 kB
VmLib: 55276 kB
VmPTE: 540 kB
VmSwap: 0 kB
Threads: 30

VmStk 栈区大概688KB还ok
看到VmData占了将近1G大小,google了一下VmData介绍说是堆区

把代码遍历了一遍,找到所有new的地方,看看有没有delete,排除了内存泄漏的情况
然后在代码中print了一把所有的new的类 cout<<sizeof(classname)<<endl;
看到这些类加起来也就100KB,一共100个微线程加起来也就10MB的样子

进一步分析

这时候就纠结了
问了几个老同事,提供了些新的思路:

  1. 内存泄漏,已经排除过,而且程序刚启动就占用了很大的内存大小
  2. 把微线程限制到1个,在程序运行过程中,打印内存使用情况

解决

这时候有个以前搞安全的同事帮忙一起看了:
cat /proc/29912/smaps
看看https://blog.csdn.net/tangtang_yue/article/details/78298067
smaps文件中,每一条记录表示进程虚拟内存空间中一块连续的区域
其中权限标识,rw-s表示可读可写的共享内存,rw-p表示可读可写的私有
还可以在里面搜索heap和stack,应该有多块连续区域,可以累加得到堆栈的大小
进一步在这个文件里搜索:
看到最大的一块区域:
5249 7fb495e28000-7fb49c228000 rw-s 00000000 00:04 1277991 /SYSV10910931 (deleted)
5250 Size: 102400 kB

/SYSV10910931 表示是一个共享内存

在/proc目录下,grep -rni “SYSV10910931” ./*/smaps
看到所有使用这块共享内存的进程
然后一个个单独 top -p 进程
判断一下哪个进程是最后可能创建这个共享内存的