2006-5-26 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;
/* Enough free memory? Not OOM. */ if (nr_free_pages() > freepages.min)//每个node,每个zone的buddy系统页面余量不足 return 0;
if (nr_free_pages() + nr_inactive_clean_pages() > freepages.low)//即使算上可以立即 return 0; //回收的页面,也少的可怜
/* Enough swap space left? Not OOM. */ si_swapinfo(&swp_info); if (swp_info.freeswap > 0)//连磁盘上的空间都不够用了 return 0;
/* Else... */ return 1; //请找个替死鬼吧 }
然后就是选择哪个进程的问题了: void oom_kill(void) { //选择一个进程 struct task_struct *p = select_bad_process();
... //授予选中的进程很高的优先级,让他尽快结束运行 p->counter = 5 * HZ; p->flags |= PF_MEMALLOC;
/* This process has hardware access, be more careful. */ //强制发送信号,结束其运行 if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO)) { force_sig(SIGTERM, p); } else { force_sig(SIGKILL, p); }
/* * Make kswapd go out of the way, so "p" has a good chance of * killing itself before someone else gets the chance to ask * for more memory. */ //只有kswapd调用此函数,所以,这就是让kswapd让出cpu //重新调度的时候,被选中的进程可可能尽快结束运行,释放资源 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; /* * The memory size of the process is the basis for the badness. */ points = p->mm->total_vm; //占有内存越多,越可能被干掉
/* * CPU time is in seconds and run time is in minutes. There is no * particular reason for this other than that it turned out to work * very well in practice. This is not safe against jiffie wraps * but we don't care _that_ much... */ 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);//占有cpu越多,即越忙,就越有可能生存 points /= int_sqrt(int_sqrt(run_time));//运行时间越久越有生存机会
/* * Niced processes are most likely less important, so double * their badness points. */ if (p->nice > 0) points *= 2;//越谦让就死的越快(不要说不公平啊)
/* * Superuser processes are usually more important, so we make it * less likely that we kill those. */ //管理员的程序需要尽力保留下来 if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) || p->uid == 0 || p->euid == 0) points /= 4;
/* * We don't want to kill a process with direct hardware access. * Not only could that mess up the hardware, but usually users * tend to only have this flag set on applications they think * of as important. */ //那些直接操作硬件的程序可以获取更多生存机会 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; }
|