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就分析完了。