zoukankan      html  css  js  c++  java
  • oom-killer, 杀掉进程的凶手

    今天发现进程一直被杀掉,几经排查,最后确认是被oom-killer杀掉了。

    在内核检测到系统内存不足后,会触发oom-killer,挑选最占用内存的进程杀掉。

    Linux 分配内存策略

    Linux内核根据应用程序的要求来分配内存,由于进程实际上并不会将分配的内存全部使用,所以,为了提高性能,内核采用了一种过度分配内存(over-commit-memory)的策略,来间接利用进程的空闲内存,提高内存的使用效率。一般来说,这没问题。但如果大多数进程都耗光自己的内存,就有麻烦了。因此此时,所有应用程序的内存之和大于物理内存。所以,必须杀掉一部分进程,一般来说,是选内存占用最大的进程杀掉。

    挑选原理

    挑选的过程由linux/mm/oom_kill.c里的 oom_badness() 函数决定,挑选的算法很直接:是那个最占用内存的进程。
    /**
     * oom_badness - heuristic function to determine which candidate task to kill
     * @p: task struct of which task we should calculate
     * @totalpages: total present RAM allowed for page allocation
     *
     * The heuristic for determining which task to kill is made to be as simple and
     * predictable as possible.  The goal is to return the highest value for the
     * task consuming the most memory to avoid subsequent oom failures.
     */
    unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
    			  const nodemask_t *nodemask, unsigned long totalpages)
    {
    	long points;
    	long adj;
    
    	if (oom_unkillable_task(p, memcg, nodemask))
    		return 0;
    
    	p = find_lock_task_mm(p);
    	if (!p)
    		return 0;
    
    	adj = (long)p->signal->oom_score_adj;
    	if (adj == OOM_SCORE_ADJ_MIN) {
    		task_unlock(p);
    		return 0;
    	}
    
    	/*
    	 * The baseline for the badness score is the proportion of RAM that each
    	 * task's rss, pagetable and swap space use.
    	 */
    	points = get_mm_rss(p->mm) + p->mm->nr_ptes +
    		 get_mm_counter(p->mm, MM_SWAPENTS);
    	task_unlock(p);
    
    	/*
    	 * Root processes get 3% bonus, just like the __vm_enough_memory()
    	 * implementation used by LSMs.
    	 */
    	if (has_capability_noaudit(p, CAP_SYS_ADMIN))
    		adj -= 30;
    
    	/* Normalize to oom_score_adj units */
    	adj *= totalpages / 1000;
    	points += adj;
    
    	/*
    	 * Never return 0 for an eligible task regardless of the root bonus and
    	 * oom_score_adj (oom_score_adj can't be OOM_SCORE_ADJ_MIN here).
    	 */
    	return points > 0 ? points : 1;
    }
    

    避免被杀掉的办法

    从上面的代码里可以看到 oom_badness() 给每个进程打分,根据 points 的高低来决定杀哪个进程,分数越低越不会被杀掉。
    这个 points 可以根据 adj 调节,root 权限的进程通常被认为很重要,不应该被轻易杀掉,所以打分的时候可以得到 3% 的优惠(adj -= 30; 分数越低越不容易被杀掉)。
    我们可以在用户空间通过操作每个进程的 oom_adj 内核参数来使得进程不容易被 OOM killer 选中杀掉。比如,如果不想 test进程被轻易杀掉的话可以找到 test运行的进程号后,调整 oom_score_adj 为 -15(注意 points 越小越不容易被杀):

    # ps aux | grep test
    test    2334  1.6  2.1 623800 4876 ?        Ssl  09:52   0:00 /usr/sbin/test
    
    # cat /proc/2334/oom_score_adj
    0
    # echo -15 > /proc/2334/oom_score_adj
    

    当然,也可以完全关闭 OOM killer,但线上生产环境最好不要这么做。

  • 相关阅读:
    反射解决了什么问题
    virtualenv
    maven pom.xml 报错
    django调用py报错 django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured.
    Django继承AbstractUser新建User Model时出现fields.E304错误
    celery 4.1下报kombu.exceptions.EncodeError: Object of type 'bytes' is not JSON serializable 处理方式
    centos 7 安装 python3.6 python3 安装步骤以及pip pip3安装挂载
    Qt中图片调用(1)
    利用批处理命令下载SOF文件的方法
    黑金开发板板上实现的液晶刷屏程序(1)
  • 原文地址:https://www.cnblogs.com/shenlinken/p/10987895.html
Copyright © 2011-2022 走看看