linux内存故障排查

上周五,在测试的一台服务器上频繁出现系统内存不够,进程被kill的现象。原以为是开源软件或自研软件内存泄漏导致的,可查看内存信息发现很奇怪,一台16GB的机器,进程总共就占了不到6GB,但memfree的内存只有160MB,cache也没有多少。
翻了很多资料,直到 https://www.cnblogs.com/tcicy/p/8299712.html
里面的这段话解答了我们的疑惑:

在VMware guest上有一个常见问题,就是VMWare ESX宿主机会通过guest上的Balloon driver(vmware_balloon module)占用guest的内存,有时占用得太多会导致guest无内存可用,这时去检查guest的/proc/meminfo只看见MemFree很少、但看不出内存的去向,原因就是Balloon driver通过alloc_pages分配内存,没有在/proc/meminfo中留下统计值,所以很难追踪。

然后问了测试部署机器的方式,建议改为vm独占模式再次复现看看。
基于这次排查的过程,顺便总结一些linux内存的信息。

一般了解linux内存的命令有 free、vmstat,但想查看丰富的内存信息,还是要查看 /proc/meminfo

MemTotal: 16266192 kB
MemFree: 201824 kB
MemAvailable: 180432 kB
Buffers: 15360 kB
Cached: 940372 kB
SwapCached: 0 kB
Active: 4475424 kB
Inactive: 462168 kB
Active(anon): 4371412 kB
Inactive(anon): 370668 kB
Active(file): 104012 kB
Inactive(file): 91500 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 608 kB
Writeback: 0 kB
AnonPages: 3982152 kB
Mapped: 261480 kB
Shmem: 760220 kB
Slab: 178816 kB
SReclaimable: 73764 kB
SUnreclaim: 105052 kB
KernelStack: 13696 kB
PageTables: 67604 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 8133096 kB
Committed_AS: 15926340 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 168972 kB
VmallocChunk: 34359341052 kB
HardwareCorrupted: 0 kB
AnonHugePages: 651264 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 163776 kB
DirectMap2M: 7176192 kB
DirectMap1G: 11534336 kB

一、 /proc/meminfo基本介绍

1. MemTotal

kernel支配的内存就是MemTotal,这个值在系统运行期间一般是固定不变的。

2. MemFree

表示系统尚未使用的内存。[MemTotal-MemFree]就是已被用掉的内存。注意:这个值不代表系统全部可用内存。

3. MemAvailable

这是个内核估算值,表示当前可用内存数量的统计值,是[可回收的内存+MemFree]。因为系统中有些内存虽然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可以回收。

4. 内存黑洞

追踪Linux系统的内存使用一直是个难题,很多人试着把能想到的各种内存消耗都加在一起,kernel text、kernel modules、buffer、cache、slab、page table、process RSS…等等,却总是与物理内存的大小对不上,这是为什么呢?因为Linux kernel并没有滴水不漏地统计所有的内存分配,kernel动态分配的内存中就有一部分没有计入/proc/meminfo中

我们知道,Kernel的动态内存分配通过以下几种接口:

1.alloc_pages/__get_free_page: 以页为单位分配
2.vmalloc: 以字节为单位分配虚拟地址连续的内存块(会自动统计到/proc/meminfo中的VmallocUsed 和 /proc/vmallocinfo)
3.slab allocator:会自动统计到proc/meminfo中的slab/SReclaimable/SUnreclaim
4.kmalloc: 以字节为单位分配物理地址连续的内存块

通过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中留下统计值,所以很难追踪。

二、 内存的去向

使用内存的,不是kernel就是用户进程,下面我们就分类讨论。

注:page cache比较特殊,很难区分是属于kernel还是属于进程,其中被进程mmap的页面自然是属于进程的了,而另一些页面没有被mapped到任何进程,那就只能算是属于kernel了。

1. 内核

内核所用内存的静态部分,并不计入MemTotal里。比如内核代码、页描述符等数据在引导阶段就分配掉了,而是算作Reserved(在dmesg中能看到)。
内核所用内存的动态部分,是通过上文提到的四个接口申请的,其中通过alloc_pages申请的内存有可能未纳入统计,就像黑洞一样。

下面讨论的都是/proc/meminfo中所统计的部分。

1.1 SLAB

SReclaimable: slab中可回收的部分。
SUnreclaim: slab中不可回收的部分。
Slab: slab中所有的内存,等于以上两者之和。

1.2 VmallocUsed

表示通过vmalloc分配的内存,但是要注意这个值不止包括了分配的物理内存,还统计了IO地址映射到内核空间的值,这个值并未消耗物理内存,所以我们要把它们排除在外。从物理内存分配的角度,我们只关心VM_ALLOC操作,这可以从/proc/vmallocinfo中的vmalloc记录看到。

1.3 kernel modules (内核模块)

kernel module所占用的内存包含在/proc/vmallocinfo的统计之中。

1.4 HardwareCorrupted

当系统检测到内存的硬件故障时,会把有问题的页面删除掉,不再使用,/proc/meminfo中的HardwareCorrupted统计了删除掉的内存页的总大小。

1.5 PageTables

用于将内存的虚拟地址翻译成物理地址,随着内存地址分配得越来越多,Page Table会增大

1.6 KernelStack

每一个用户线程都会分配一个kernel stack(内核栈),用户态的代码不能访问。
Kernel stack(内核栈)是常驻内存的,既不包括在LRU lists里,也不包括在进程的RSS/PSS内存里,所以我们认为它是kernel消耗的内存。统计值是/proc/meminfo的KernelStack。

1.7 Bounce

有些老设备只能访问低端内存,当应用程序发出一个I/O 请求,DMA的目的地址却是高端内存时,内核将在低端内存中分配一个临时buffer作为跳转,把位于高端内存的缓存数据复制到此处。这种额外的数据拷贝被称为“bounce buffering”,会降低I/O 性能。
大量分配的bounce buffers 也会占用额外的内存。

2. 用户进程

/proc/meminfo统计的是系统全局的内存使用状况,想查看单个进程的情况要看/proc//下的smaps等等。

2.1 Hugepages

Hugepages在/proc/meminfo中是被独立统计的,与其它统计项不重叠,既不计入进程的RSS/PSS中,又不计入LRU Active/Inactive,也不会计入cache/buffer。如果进程使用了Hugepages,它的RSS/PSS不会增加。
HugePages_Total 对应内核参数 vm.nr_hugepages,也可以在运行中的系统上直接修改 /proc/sys/vm/nr_hugepages,修改的结果会立即影响空闲内存 MemFree的大小,因为HugePages在内核中独立管理,只要一经定义,无论是否被使用,都不再属于free memory。

2.2 AnonHugePages

AnonHugePages统计的是Transparent HugePages (THP),THP与Hugepages不是一回事,区别很大。

AnonHugePages与/proc/meminfo的其他统计项有重叠,首先它被包含在AnonPages之中,而且在/proc//smaps中也有单个进程的统计,与进程的RSS/PSS是有重叠的,如果用户进程用到了THP,进程的RSS/PSS也会相应增加

2.3 LRU

LRU是Kernel的页面回收算法(Page Frame Reclaiming)使用的数据结构,Page cache和所有用户进程的内存(kernel stack和huge pages除外)都在LRU lists上。

LRU lists包括如下几种,在/proc/meminfo中都有对应的统计值:

LRU_INACTIVE_ANON – 对应 Inactive(anon)
LRU_ACTIVE_ANON – 对应 Active(anon)
LRU_INACTIVE_FILE – 对应 Inactive(file)
LRU_ACTIVE_FILE – 对应 Active(file)
LRU_UNEVICTABLE – 对应 Unevictable

Inactive list里的是长时间未被访问过的内存页,Active list里的是最近被访问过的内存页,LRU算法利用Inactive list和Active list可以判断哪些内存页可以被优先回收。

LRU中不包含HugePages_*。
LRU包含了 Cached 和 AnonPages。

2.4 Shmem

/proc/meminfo中的Shmem统计的内容包括:shared memory和tmpfs;

2.5 AnonPages

前面提到用户进程的内存页分为两种:file-backed pages(与文件对应的内存页),和anonymous pages(匿名页)。Anonymous pages(匿名页)的数量统计在/proc/meminfo的AnonPages中。

2.6 Mapped
2.7 Cached
2.8 SwapCached
2.9 Mlocked
2.10 Buffers

3. Linux的内存都用到哪里去了?

尽管不可能精确统计Linux系统的内存,但大体了解还是可以的。

kernel内存的统计

统计方式应该比较明确,即
【Slab+ VmallocUsed + PageTables + KernelStack + HardwareCorrupted + Bounce + X】

注:X表示直接通过alloc_pages/__get_free_page分配的内存,没有在/proc/meminfo中统计,不知道有多少,就像个黑洞。

用户进程的内存

主要有三种统计口径:

  1. 围绕LRU进行统计
    【(Active + Inactive + Unevictable) + (HugePages_Total * Hugepagesize)】
  2. 围绕Page Cache进行统计
    当SwapCached为0的时候,用户进程的内存总计如下:
    【(Cached + AnonPages + Buffers) + (HugePages_Total * Hugepagesize)】
    当SwapCached不为0的时候,以上公式不成立,因为SwapCached可能会含有Shmem,而Shmem本来被含在Cached中,一旦swap-out就从Cached转移到了SwapCached,可是我们又不能把SwapCached加进上述公式中,因为SwapCached虽然不与Cached重叠却与AnonPages有重叠,它既可能含有Shared memory又可能含有Anonymous Pages。
  3. 围绕RSS/PSS进行统计
    把/proc/[1-9]*/smaps 中的 Pss 累加起来就是所有用户进程占用的内存,但是还没有包括Page Cache中unmapped部分、以及HugePages,所以公式如下:
    ΣPss + (Cached – mapped) + Buffers + (HugePages_Total * Hugepagesize)
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值