mm/oom_kill.c
*
* 忙,并且忙了很久,占有的少,和权利大的靠边,并毫不谦让,直接出手的有更
* 多生还机会
*
超级纯粹的一个模块,实现out of memory killer.当内存严重不足的时候选择
一个"弱者",同过强制信号kill掉,释放出内存。
提供了两个借口:
void oom_kill(void)
int out_of_memory(void)
并且只有一个地方使用,vmscan.c:
int kswapd(void *unused)
{
........
else if (out_of_memory()) {
oom_kill();
}
}
分析filemap.c的时候,了解过kswapd的作用,罗列一下:
*****kswapd (mm/vmscan.c)
+---->do_try_to_free_pages (如果内存已经不够用)
+-->page_launder
| +-->扫描 <inactive_dirty_list>
| +-->对dirty页启动回写(包括mapping和buffer cache)
+-->refill_inactive
+-->refill_inactive_scan
+-->扫描<active_list>,选择合适页面移入
<inactive_dirty_list>
+-->swap_out,对进程启动页面换出
+-->try_to_swap_out将选中页面放入
<inactive_dirty_list>
+----->refill_inactive_scan
先来看看什么叫做内存严重不足:
int out_of_memory(void)
{
struct sysinfo swp_info;
if (nr_free_pages() > freepages.min) return 0;
if (nr_free_pages() + nr_inactive_clean_pages() > freepages.low) return 0;
si_swapinfo(&swp_info);
if (swp_info.freeswap > 0) return 0;
return 1;}
然后就是选择哪个进程的问题了:
void oom_kill(void)
{ struct task_struct *p = select_bad_process();
... p->counter = 5 * HZ;
p->flags |= PF_MEMALLOC; if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO)) {
force_sig(SIGTERM, p);
} else {
force_sig(SIGKILL, p);
} current->policy |= SCHED_YIELD;
schedule();
return;
}
kswapd(oom_kill)选中要kill的进程,发送一个信号给这个进程,然后kswapd让
出cpu,是选中的进程可以得到调度.当选中的进程开始运行的时候,因为有一个信号
处于peding状态,所以系统建立一个运行signal的环境,并开始处理信号.最后被选
中的进程退出运行,释放资源.至于更详细的过程等到分析信号的时候再议.
select_bad_process选择badness值最高的进程,我们来看看什么样的进程最有
可能为系统牺牲:
static int badness(struct task_struct *p)
{
int points, cpu_time, run_time;
if (!p->mm)
return 0;
points = p->mm->total_vm;
cpu_time = (p->times.tms_utime + p->times.tms_stime) >> (SHIFT_HZ + 3);
run_time = (jiffies - p->start_time) >> (SHIFT_HZ + 10);
points /= int_sqrt(cpu_time); points /= int_sqrt(int_sqrt(run_time));
if (p->nice > 0)
points *= 2; if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) ||
p->uid == 0 || p->euid == 0)
points /= 4; if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO))
points /= 4;
#ifdef DEBUG
printk(KERN_DEBUG "OOMkill: task %d (%s) got %d points\n",
p->pid, p->comm, points);
#endif
return points;
}