打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
OOM(out
分类: 内存管理 2013-04-27 16:47 1001人阅读 评论(0) 收藏 举报

Chipset: MSM8X25Q

Codebase: Android4.1

Kernel: 3.4.0

 

概念:

         OOMkiller,即out of memory killer,是linux下面的一种管理当内存耗尽时的处理机制。当内存较少时,OOM会遍历整个进程链表,然后根据进程的内存使用情况以及它的oom score值最终找到得分较高的进程,然后发送kill信号将其杀掉。

         伙伴系统中在分配内存时会做判断,当内存不足时,会调用核心函数out_of_memory(), 函数位于文件oom_kill.c@kernel/mm.

         下面先分析out_of_memory()。

out_of_memory():

  1. void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,  
  2.         int order, nodemask_t *nodemask, bool force_kill)  
  3. {  
  4.     const nodemask_t *mpol_mask;  
  5.     struct task_struct *p;  
  6.     unsigned long totalpages;  
  7.     unsigned long freed = 0;  
  8.     unsigned int points;  
  9.     enum oom_constraint constraint = CONSTRAINT_NONE;  
  10.     int killed = 0;  
  11.   
  12. ~~snip  
  13. /*如果当前已经有Pending的kill信号,那么马上返回。  
  14. 毕竟oom最中为了free memory而执行sig kill。*/  
  15.     if (fatal_signal_pending(current)) {  
  16.         set_thread_flag(TIF_MEMDIE);  
  17.         return;  
  18.     }  
  19.   
  20. ~~snip  
  21.     /*用户空间可以通过/proc/sys/vm/panic_on_oom来改变oom的行为,  
  22. 1表示oom的时候直接panic,0就只杀掉”best”进程而让系统继续运行。*/  
  23.     check_panic_on_oom(constraint, gfp_mask, order, mpol_mask);  
  24.   
  25.     read_lock(&tasklist_lock);  
  26.       
  27. /*同样/proc/sys/vm/ oom_kill_allocating_task为true时表示直接将当前分配的task  
  28. 给kill掉。*/  
  29. if (sysctl_oom_kill_allocating_task &&  
  30.         !oom_unkillable_task(current, NULL, nodemask) &&  
  31.         current->mm) {  
  32.         oom_kill_process(current, gfp_mask, order, 0, totalpages, NULL,  
  33.                  nodemask,  
  34.                  "Out of memory (oom_kill_allocating_task)");  
  35.         goto out;  
  36.     }  
  37.     /*根据当前task的内存以oom score信息得到point值最高的那个。*/  
  38.     p = select_bad_process(&points, totalpages, NULL, mpol_mask,  
  39.                    force_kill);  
  40.     /* Found nothing?!?! Either we hang forever, or we panic. */  
  41.     if (!p) {  
  42.         dump_header(NULL, gfp_mask, order, NULL, mpol_mask);  
  43.         read_unlock(&tasklist_lock);  
  44.         panic("Out of memory and no killable processes...\n");  
  45.     }  
  46.     if (PTR_ERR(p) != -1UL) {  
  47.         /*唔,被杀了,苦逼!*/  
  48.         oom_kill_process(p, gfp_mask, order, points, totalpages, NULL,  
  49.                  nodemask, "Out of memory");  
  50.         killed = 1;  
  51.     }  
  52. out:  
  53.     read_unlock(&tasklist_lock);  
  54.   
  55.     /*  
  56.      * Give "p" a good chance of killing itself before we  
  57.      * retry to allocate memory unless "p" is current  
  58.      */  
  59.     if (killed && !test_thread_flag(TIF_MEMDIE))  
  60.         schedule_timeout_uninterruptible(1);  
  61. }  

select_bad_process():

  1. static struct task_struct *select_bad_process(unsigned int *ppoints,  
  2.         unsigned long totalpages, struct mem_cgroup *memcg,  
  3.         const nodemask_t *nodemask, bool force_kill)  
  4. {  
  5.     struct task_struct *g, *p;  
  6.     struct task_struct *chosen = NULL;  
  7.     *ppoints = 0;  
  8.     /*遍历所有进程*/  
  9.     do_each_thread(g, p) {  
  10.         unsigned int points;  
  11.         /*处于退出的进程就不管了*/  
  12.         if (p->exit_state)  
  13.             continue;  
  14.         /*有些核心的线程不能杀,如init, kernel_thread*/  
  15.         if (oom_unkillable_task(p, memcg, nodemask))  
  16.             continue;  
  17.         /*正在被oom killing的进程也不管。*/  
  18.         if (test_tsk_thread_flag(p, TIF_MEMDIE)) {  
  19.             if (unlikely(frozen(p)))  
  20.                 __thaw_task(p);  
  21.             if (!force_kill)  
  22.                 return ERR_PTR(-1UL);  
  23.         }  
  24.         if (!p->mm)  
  25.             continue;  
  26.   
  27.         if (p->flags & PF_EXITING) {  
  28.             if (p == current) {  
  29.                 chosen = p;  
  30.                 *ppoints = 1000;  
  31.             } else if (!force_kill) {  
  32.                 /*  
  33.                  * If this task is not being ptraced on exit,  
  34.                  * then wait for it to finish before killing  
  35.                  * some other task unnecessarily.  
  36.                  */  
  37.                 if (!(p->group_leader->ptrace & PT_TRACE_EXIT))  
  38.                     return ERR_PTR(-1UL);  
  39.             }  
  40.         }  
  41.         /*计算task对应的points*/  
  42.         points = oom_badness(p, memcg, nodemask, totalpages);  
  43.         /*如果此task比上次的points要大,那么保存point.*/  
  44.         if (points > *ppoints) {  
  45.             chosen = p;  
  46.             *ppoints = points;  
  47.         }  
  48.     } while_each_thread(g, p);  
  49.   
  50.     return chosen;  
  51. }  

oom_badness():

  1. unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *memcg,  
  2.               const nodemask_t *nodemask, unsigned long totalpages)  
  3. {  
  4.     long points;  
  5.   
  6.     if (oom_unkillable_task(p, memcg, nodemask))  
  7.         return 0;  
  8.   
  9.     p = find_lock_task_mm(p);  
  10.     if (!p)  
  11.         return 0;  
  12.     /*oom_score_adj为-1000的不做处理,此值可以通过/proc/pid_num/oom_score_adj设置,范围为-1000 ~ 1000,值越大越容易被oom kill掉。*/  
  13.     if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {  
  14.         task_unlock(p);  
  15.         return 0;  
  16.     }  
  17.   
  18.     /*  
  19.      * The memory controller may have a limit of 0 bytes, so avoid a divide  
  20.      * by zero, if necessary.  
  21.      */  
  22.     if (!totalpages)  
  23.         totalpages = 1;  
  24.   
  25.     /* get_mm_rss获取当前用户空间使用文件和匿名页占有内存数,nr_ptes 获取  
  26. 当前保存页表使用的内存。*/  
  27.     points = get_mm_rss(p->mm) + p->mm->nr_ptes;  
  28.     /*获取交换内存使用的内存数*/  
  29.     points += get_mm_counter(p->mm, MM_SWAPENTS);  
  30.     /*每个task同等计算,可不管。*/  
  31.     points *= 1000;  
  32.     points /= totalpages;  
  33.     task_unlock(p);  
  34.   
  35.     /*当该进程具有CAP_SYS_ADMIN能力,那么Point降低,因为具有ADMIN权限的  
  36. Task是被认为表现良好的。 */  
  37.     if (has_capability_noaudit(p, CAP_SYS_ADMIN))  
  38.         points -= 30;  
  39.   
  40.     /*加上oom_score_adj,范围从-1000 ~ 1000. */  
  41.     points += p->signal->oom_score_adj;  
  42.   
  43.     /*  
  44.      * Never return 0 for an eligible task that may be killed since it's  
  45.      * possible that no single user task uses more than 0.1% of memory and  
  46.      * no single admin tasks uses more than 3.0%.  
  47.      */  
  48.     if (points <= 0)  
  49.         return 1;  
  50.     /*1000封顶*/  
  51.     return (points < 1000) ? points : 1000;  
  52. }  

oom_kill_process():

  1. static void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,  
  2.                  unsigned int points, unsigned long totalpages,  
  3.                  struct mem_cgroup *memcg, nodemask_t *nodemask,  
  4.                  const char *message)  
  5. {  
  6.     struct task_struct *victim = p;  
  7.     struct task_struct *child;  
  8.     struct task_struct *t = p;  
  9.     struct mm_struct *mm;  
  10.     unsigned int victim_points = 0;  
  11.     static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,  
  12.                           DEFAULT_RATELIMIT_BURST);  
  13.   
  14.     /*  
  15.      * If the task is already exiting, don't alarm the sysadmin or kill  
  16.      * its children or threads, just set TIF_MEMDIE so it can die quickly  
  17.      */  
  18.     if (p->flags & PF_EXITING) {  
  19.         set_tsk_thread_flag(p, TIF_MEMDIE);  
  20.         return;  
  21.     }  
  22.   
  23.     if (__ratelimit(&oom_rs))  
  24.         dump_header(p, gfp_mask, order, memcg, nodemask);  
  25.   
  26.     task_lock(p);  
  27.     pr_err("%s: Kill process %d (%s) score %d or sacrifice child\n",  
  28.         message, task_pid_nr(p), p->comm, points);  
  29.     task_unlock(p);  
  30.   
  31.     /*当前被选定子进程的mm和父进程不一样时,找到其中最高point  
  32. 的children task,然后替代父进程被杀掉,所以当一个进程有多个子进程并且  
  33. 真用较多内存时,子进程有可能被杀掉,而父进程还可以活着。 */  
  34.     do {  
  35.         list_for_each_entry(child, &t->children, sibling) {  
  36.             unsigned int child_points;  
  37.   
  38.             if (child->mm == p->mm)  
  39.                 continue;  
  40.             /*  
  41.              * oom_badness() returns 0 if the thread is unkillable  
  42.              */  
  43.             child_points = oom_badness(child, memcg, nodemask,  
  44.                                 totalpages);  
  45.             if (child_points > victim_points) {  
  46.                 victim = child;  
  47.                 victim_points = child_points;  
  48.             }  
  49.         }  
  50.     } while_each_thread(p, t);  
  51.   
  52.     victim = find_lock_task_mm(victim);  
  53.     if (!victim)  
  54.         return;  
  55.   
  56.     /* mm cannot safely be dereferenced after task_unlock(victim) */  
  57.     mm = victim->mm;  
  58.     pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n",  
  59.         task_pid_nr(victim), victim->comm, K(victim->mm->total_vm),  
  60.         K(get_mm_counter(victim->mm, MM_ANONPAGES)),  
  61.         K(get_mm_counter(victim->mm, MM_FILEPAGES)));  
  62.     task_unlock(victim);  
  63.   
  64.     /*  
  65.      只要mm是一样的,也就是说共享内存的进程,都会和当前找到最高point的  
  66. 指定进程一起被杀掉。 */  
  67.     for_each_process(p)  
  68.         if (p->mm == mm && !same_thread_group(p, victim) &&  
  69.             !(p->flags & PF_KTHREAD)) {  
  70.             if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)  
  71.                 continue;  
  72.   
  73.             task_lock(p);   /* Protect ->comm from prctl() */  
  74.             pr_err("Kill process %d (%s) sharing same memory\n",  
  75.                 task_pid_nr(p), p->comm);  
  76.             task_unlock(p);  
  77.             /*发送 SIGKILL信号。*/  
  78.             do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);  
  79.         }  
  80.   
  81.     set_tsk_thread_flag(victim, TIF_MEMDIE);  
  82.     do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, true);  
  83. }  

所以,out_of_memory()做的任务就是遍历系统全部进程,然后根据内存使用情况以及oom_score_adj的值计算得到一个point, 最终将最高point的task给kill掉。

相关知识:

1.      Malloc会引起OOM killer,可参考:

http://blog.dccmx.com/2011/04/oom-killer-on-linux

2.      OOM killer值是管理计算lowmemory部分,即使High memory有很多空闲内存。

3.      进程rss的计算可参考此文:

http://filwmm1314.blog.163.com/blog/static/2182591920121016541582/

4.      影响到oom killer行为的文件有:

/proc/sys/vm/overcommit_memory

/proc/sys/vm/panic_on_oom

/proc/sys/vm/oom_kill_allocating_task

/porc/pid_xxx/oom_score_adj

 

2013/04/27





本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
linux线程浅析
zz关于linux线程
直接内存回收中的等待队列
Special Features of Linux Memory Management Mechanism
OOM killer "Out of Memory: Killed process" SO...
Linux Out
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服