【系统运维】Out of Memory(OOM)的原理与内存回收相关配置

TangLu 运维 2021-12-22 1460 0

一、什么是OOM

OOM即out of memory,即系统在自身内存耗尽时的自我拯救措施。当系统内存不足时,由系统选择一个进程杀死以释放出内存,这个被杀的进程通常是使用内存最高的程序。这里使用了"通常"一词是因为系统在进行选择时,会参考多个因素。除了进程占用内存外,还和进程运行的时间、进程优先级、是否为root用户进程、子进程个数以及用户控制参数oom_adj相关。当触发OOM后,系统会使用select_bad_process函数遍历所有进程,并按照多个因素进行打分,最终oom_score分数最高的进程就是被杀掉的对象。


二、oom_adj设置

前面提到用户通过参数oom_adj可以影响OOM分数,而这个参数通过/proc/<pid>/oom_adj文件进行控制。该文件可配置范围为-17到15,如果配置为-17则代表该进程不会被系统杀死。所以如果有某个进程不能发生OOM的话,可以将该服务oom_adj 为-17


三、overcommit_memory

除了oom_adj文件外,还需要注意/proc/sys/vm/overcommit_memory的配置,该文件支持配置的值为0,1,2

· 当参数为0时为启发式OOM,即当申请的虚拟内存不是很夸张的大于物理内存时,系统会允许该申请。但是当进程申请的虚拟内存很夸张的大于物理内存,则产生OOM。例如只有Redis服务器内存为8G,Redis占用了3G的物理内存,但是在虚拟内存中存在24G数据,这个时候执行bgsave命令后,子进程会申请24G的虚拟内存,这明显大于很物理内存,然后触发OOM

· 当参数为1时则永远允许overmemory内存申请,即不管申请多大的虚拟内存系统会都允许,直到系统内存耗尽产生OOM。在上面那个Redis案例中,如果overcommit_memory=1是不会产生OOM的,因为物理内存足够
· 当参数为2时则永远都不能超出某个限定额的内存申请,这个限定额为SWAP+RAM* 系数(/proc/sys/vm/overcmmit_ratio,默认50%,可以自己调整),如果资源用光,后面任何尝试申请内存的行为都会返回错误,此时没法运行任何新程序


四、系统内存回收

当系统内存不足时有两种方式进行内存释放,一种是手动回收,另一种是系统自己触发的内存回收。如果发现系统已用内存和实际使用内存有较大出入,可以通过查看Slab消耗进行分析

cat /proc/meminfo|grep Slab   #查看slab总共占用内存
cat /proc/slabinfo |awk '{if($3*$4/1024/1024 > 100){print $1,$3*$4/1024/1024 "MB"} }'    #查看占用内存的具体缓存组件,输出大于100M的,其中proc_inode_cache就是可以进行手动回收的
echo 2 > /proc/sys/vm/drop_caches


1、手动回收内存

通过/proc/sys/vm/drop_caches文件可以手动释放pagecache中的内存,需要注意如果pagecache中有脏数据时,通过drop_caches是不能释放的,必须通过sync命令将脏数据刷新到磁盘再通过操作 drop_caches释放pagecache

· 当drop_caches为1时将释放pagecache中可释放的部分(有些 cache 是不能通过这个释放的)

· 当drop_caches为2时将释放dentries和inodes缓存

· 当drop_caches为3时同时释放上述两项

echo 1 >> /proc/sys/vm/drop_caches


2、系统自动回收内存

当系统内存不足时会有一套自我整理内存,会尽可能的释放内存。如果这套机制工作后依然不能释放足够多的内存,则发生OOM。这个自动回收内存原理是通过kswapd进程去周期性的检查内存使用情况,当内存水平低于某个极限阈值时会直接发出内存回收。由于SWAP发生后很占用系统IO,为了避免突发性的大量SWAP发生,导致服务器不能对外提供服务,可以通过swappiness参数进行相关设置,该参数对应文件为/proc/sys/vm/swappiness。该值越高越可能使用SWAP的方式回收内存,最大值为100。关于SWAP相关设置,可参考《【系统运维】SWAP交换分区介绍与配置教程

评论