记录一次虚拟机内存黑洞的追查过程
最近将一台开发机迁移到了虚拟机上,运维同事给的配置跟之前一样,64G内存,可是同事用着没几天就感觉很卡,之前物理机的时候没出现过这个问题。先记录下追查过程1.free -m和top都查看了当前内存使用情况# free -mtotalusedfreesharedbuff/cacheavailableMem:62815339182702416
最近将一台开发机迁移到了虚拟机上,运维同事给的配置跟之前一样,64G内存,可是同事用着没几天就感觉很卡,之前物理机的时候没出现过这个问题。先记录下追查过程
1.free -m和top都查看了当前内存使用情况
# free -m
total used free shared buff/cache available
Mem: 62815 33918 27024 16 1872 28366
Swap: 4095 0 4095 4095 0 4095
# top
top - 18:12:22 up 2 days, 21:16, 6 users, load average: 1.12, 0.73, 0.69
Tasks: 339 total, 1 running, 338 sleeping, 0 stopped, 0 zombie
%Cpu(s): 2.4 us, 1.0 sy, 0.0 ni, 96.2 id, 0.2 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 64323240 total, 27578116 free, 34827600 used, 1917524 buff/cache
KiB Swap: 4194300 total, 4194300 free, 0 used. 28952176 avail Mem
这里看到差不多使用了35G
2.统计top中进程的res字段,汇总可见的内存使用数,也可以直接查看/proc/pid/smaps
####### get_res.awk start
{
if(NR >= 8)
{
start = index($6, "g");
if(start != 0)
{
val = substr($6, 0, start -1) * 1024 * 1024;
mem_sum += val;
print $6, substr($6, 0, start -1);
}
else
{
val = $6;
mem_sum += val;
}
}
}
END{ printf("%d\n", mem_sum); }
####### end
# top -b -n 1 | awk -f /tmp/get_res.awk
5821396
# grep Pss /proc/[1-9]*/smaps | awk '{total+=$2}; END {print total}'
5583365
可以看到,可见的内存使用数也就6G不到,这中间相差了接近30G
3.查看free和top源码,寻找数据来源(procps-ng / procps · GitLab)
# grep MEMINFO_MEM_USED -R . -n
./proc/meminfo.h:92: MEMINFO_MEM_USED, // ul_int derived from MEM_TOTAL - MEM_BUFFERS - MEM_CACHED_ALL - MEM_FREE
./top/top.c:265: MEMINFO_MEM_FREE, MEMINFO_MEM_USED, MEMINFO_MEM_TOTAL,
./free.c:348: printf(" %11s", scale_size(MEMINFO_GET(mem_info, MEMINFO_MEM_USED, ul_int), flags, args));
./free.c:394: MEMINFO_GET(mem_info, MEMINFO_MEM_USED, ul_int) +
./vmstat.c:203: MEMINFO_MEM_USED,
略去代码部分,可以看到used这个字段是从/proc/meminfo中获得的,计算过程如下
MEMINFO_MEM_CACHED_ALL, // ul_int derived from MEM_CACHED + MEM_SLAB_RECLAIM
MEMINFO_MEM_USED, // ul_int derived from MEM_TOTAL - MEM_BUFFERS - MEM_CACHED_ALL - MEM_FREE
可见used是一个从其他字段推导出来的值,total,buffers,cache,free这几项是有确定的统计值的
4.详细了解 /pro/meminfo,/proc/meminfo之谜 | Linux Performance
内存黑洞
追踪Linux系统的内存使用一直是个难题,很多人试着把能想到的各种内存消耗都加在一起,kernel text、kernel modules、buffer、cache、slab、page table、process RSS…等等,却总是与物理内存的大小对不上,这是为什么呢?因为Linux kernel并没有滴水不漏地统计所有的内存分配,kernel动态分配的内存中就有一部分没有计入/proc/meminfo中。
我们知道,Kernel的动态内存分配通过以下几种接口:
- alloc_pages/__get_free_page: 以页为单位分配
- vmalloc: 以字节为单位分配虚拟地址连续的内存块
- slab allocator
- kmalloc: 以字节为单位分配物理地址连续的内存块,它是以slab为基础的,使用slab层的general caches — 大小为2^n,名称是kmalloc-32、kmalloc-64等(在老kernel上的名称是size-32、size-64等)。
通过slab层分配的内存会被精确统计,可以参见/proc/meminfo中的slab/SReclaimable/SUnreclaim;
通过vmalloc分配的内存也有统计,参见/proc/meminfo中的VmallocUsed 和 /proc/vmallocinfo(下节中还有详述);
而通过alloc_pages分配的内存不会自动统计,除非调用alloc_pages的内核模块或驱动程序主动进行统计,否则我们只能看到free memory减少了,但从/proc/meminfo中看不出它们具体用到哪里去了。比如在VMware guest上有一个常见问题,就是VMWare ESX宿主机会通过guest上的Balloon driver(vmware_balloon module)占用guest的内存,有时占用得太多会导致guest无内存可用,这时去检查guest的/proc/meminfo只看见MemFree很少、但看不出内存的去向,原因就是Balloon driver通过alloc_pages分配内存,没有在/proc/meminfo中留下统计值,所以很难追踪。
5.验证
# lsmod |grep balloon
vmw_balloon 18094 0
证明的确有balloon driver在,当前不敢直接rmmod,要等运维同事确认
更多推荐
所有评论(0)