定位一个oom问题
当系统出现oom问题时,我们一般的定位思路是怎样的?
系统OOM常见的原因有:
1、用户态内存需求过多,资源不足; 2、大页配置不正确; 3、水位线值异常; 4、slab内存过多; 5、rcu异常;
OOM问题定位步骤如下:
1、查看/proc/meminfo,查看用户态内存和内核态内存分别占用多少内存;通过top命令查看占用内存较多的前10个进程;
1、用户态内存使用过多; 2、top 10的进程存在非虚拟机进程,通常情况下,使用内存最多的是虚拟机进程。如果是费虚拟机进程出现在了前top10里,那么有可能是这个进程有内存泄露的问题;
3、如果top10进程都是虚拟机进程,确认虚拟机的规格是不是超过上限了;
2、查看大页配置是否正确,确认是否大量大页没有使用。如果大页还有剩余,虚拟机都是使用的小页,那么有可能是大页配置的不正确;
3、查看linux系统水位线配置是否正常,水位线,一般配置在文件/proc/sys/vm/min_free_kbytes,水位线控制有3个值,min,low,high,当可用内存低于low时,系统开始回收内存。当可用内存大于high时,停止回收,当可用内存低于min值时,禁止给用户态进程分配内存;当水位线值被误修改为很大的值时,很容易造成用户态内存不足。
4、查看/proc/slabinfo,内核及模块通过kmalloc分配的内存是通过slab管理的,如果这部分内存一直不释放,会导致slab内存使用过多,出现OOM;查看slabinfo,更正常系统对比,检查异常的slab,根据slab名称查看对应的释放代码,排查问题;
5、RCU异常,RCU保护的指针指向的内存释放,需要调用call_rcu或者kfree_rcu来释放,当所有cpu都经过一个grace period后,内存在能真正释放。cpu上触发一次调度后,grace period结束。如果出现了RCU异常,某一个cpu上的grace period结束不了,通过RCU释放的内存就无法真正的释放。一般造成RCU异常的是某一个CPU上发生了死循环。
crash> struct rcu_state.rda rcu_sched_state rda = 0x141e0 crash> struct rcu_date.qlen 0x141e0:all
如上命令可以打印出每个cpu上rcu中的qlen的大小, qlen为等待释放的object数量,一般情况下这个值在1000以下,如果其他cpu的qlen值都过大,只有一个cpu的qlen值小,那么有可能是这个qlen正常的cpu出现了死循环。
有一次出现OOM,我们就发现一个cpu中的rcu qlen值较小,其他cpu上的rcu qlen值很大,后来重点看这个cpu上的调用栈,分析代码,打印log,后来发现,在这个cpu上由于硬件问题出现了死循环,最后导致一直没有完成一个grace period,后面几个cpu的rcu就没有真正的完成释放,所以他们的qlen值很大,slabinfo查看object数量也很大。