12.3.2 LM Killer机制的实现
接下来分析LM Killer的实现,代码如下:
//定义shrinker类型的lowmem_shrinker结构体
static struct shrinker lowmem_shrinker={
.shrink=lowmem_shrink,//shrinker的回调函数
.seeks=DEFAULT_SEEKS*16
};
static int__init lowmem_init(void)
{
register_shrinker(&lowmem_shrinker);
return 0;
}
static void__exit lowmem_exit(void)
{
unregister_shrinker(&lowmem_shrinker);
}
module_init(lowmem_init);//模块初始化时,注册shrinker方法
module_exit(lowmem_exit);//模块退出时,卸载shrinker方法
在模块初始化时,通过lowmem_init方法调用register_shrinker方法注册一个shrinker类型的lowmem_shrinker。shrinker与Linux内存页回收有关,当需要回收内存页时,便会回调shrink指定的方法,本例中要回调的方法为lowmem_shrink。
lowmem_shrinker在驱动层指定了OOM adj等级和最小内存阈值,代码如下:
//OOM adj等级
static int lowmem_adj[6]={//注意,数组大小为6
0,
1,
6,
12,//只指定了4个值,其余为默认
};
//最小内存阈值
static int lowmem_minfree[6]={//数组大小为6,只指定了4个值,其余为默认
3512,/6MB*/
21024,/8MB*/
41024,/16MB*/
161024,/64MB*/
};
lowmem_shrink函数被触发后的执行代码如下:
static int lowmem_shrink(struct shrinkers, struct shrink_controlsc)
{
struct task_struct*tsk;//Linux进程的表示形式
struct task_struct*selected=NULL;
int rem=0;
int tasksize;
int i;
int min_score_adj=OOM_SCORE_ADJ_MAX+1;
int selected_tasksize=0;//被选择的进程,占用内存情况
int selected_oom_score_adj;//被选择进程的OOM adj
int array_size=ARRAY_SIZE(lowmem_adj);//OOM adj等级的数量
int other_free=global_page_state(NR_FREE_PAGES);//空闲页数量
int other_file=global_page_state(NR_FILE_PAGES)-
global_page_state(NR_SHMEM);//缓存页数量
……
for(i=0;i<array_size;i++){
//计算当前满足哪个最小内存阈值
if(other_free<lowmem_minfree[i]&&other_file<lowmem_minfree[i]){
//获取该内存阈值对应的OOM adj
min_score_adj=lowmem_adj[i];
break;
}
}
……
rem=global_page_state(NR_ACTIVE_ANON)+
global_page_state(NR_ACTIVE_FILE)+
global_page_state(NR_INACTIVE_ANON)+
global_page_state(NR_INACTIVE_FILE);
//不需要回收进程,说明此时剩余内存页大于64MB(目前最小内存阈值的最大值)
if(sc->nr_to_scan<=0||min_score_adj==OOM_SCORE_ADJ_MAX+1){
return rem;
}
selected_oom_score_adj=min_score_adj;
rcu_read_lock();
for_each_process(tsk){//遍历进程
struct task_struct*p;
int oom_score_adj;
……
//获取进程的OOM adj值
oom_score_adj=p->signal->oom_score_adj;
if(oom_score_adj<min_score_adj){
task_unlock(p);
continue;
}
tasksize=get_mm_rss(p->mm);//获取进程的内存使用情况
……
if(selected){
//选择OOM adj值较大的进程
if(oom_score_adj<selected_oom_score_adj)
continue;
//OOM adj相同的情况下,选择使用内存更多的进程
if(oom_score_adj==selected_oom_score_adj&&
tasksize<=selected_tasksize)
continue;
}
selected=p;
selected_tasksize=tasksize;
selected_oom_score_adj=oom_score_adj;
}
if(selected){
……
send_sig(SIGKILL, selected,0);//发送SIGKILL信号“杀死”选择的进程
set_tsk_thread_flag(selected, TIF_MEMDIE);
rem-=selected_tasksize;
}
……
return rem;
}
lowmem_shrink选择进程“杀死”的三条原则是:
OOM adj越大的进程越容易被“杀死”。
相同OOM adj的进程,占用内存越大的越容易被“杀死”。
未达到最小内存阈值的最大值时,不会选择进程“杀死”。
至此LM Killer就分析完了。