码迷,mamicode.com
首页 > 其他好文 > 详细

Lowmemorykiller笔记

时间:2015-04-29 21:42:06      阅读:564      评论:0      收藏:0      [点我收藏+]

标签:

从zygote孵化出来的进程都会记录在ActivityManagerService.mLruProcesses列表中,由ActivityManagerService进行统一管理,ActivityManagerService核心业务之一便是时时更新进程的状态,根据状态计算出进程对应的OomAdj值,这个值会传递到kernel中去,kernel有个低内存回收机制,在内存达到一定阀值时会触发清理OomAdj值高的进程,这边是Lowmemorykiller工作原理。

第一部分:进程OomAdj值的设置


技术分享

这个流程中,ActivityManagerService会计算出进程的OomAdj值,然后通过Lmkd这个native进程来将OomAdj值分别写入对应进程的oom_score_adj节点去。可以通过cat /proc/%pid/oom_score_adj来查看每个进程的OomAdj值。

注意:

①OomAdj值越小表示优先级越高,越不容易被kill。

②ActivityManagerService中为进程设定的OomAdj值取值范围为-16~16,设定到oom_score_adj节点中的值是经过 OomAdj*1000/17 公式计算出来的。

③native进程OomAdj值默认为-17,也就是说native进程oom_score_adj节点中值必是-1000.


第二部分:核心调用lowmem_shrink()

这个函数主要根据当前剩余内存与lowmem_minfree来评判当前内存已经达到哪个阀值以下(每个阀值都对应一个lowmem_adj值),进而得出一个lowmem_adj基准值(只有OomAdj值大于这个lowmem_adj基准值的进程才可能被杀)。

代码在/drivers/staging/android/lowmemorykiller.c

static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
{
	struct task_struct *tsk;
	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;
	int array_size = ARRAY_SIZE(lowmem_adj);
	int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
	int other_file = global_page_state(NR_FILE_PAGES) -
						global_page_state(NR_SHMEM);

	if (lowmem_adj_size < array_size)
		array_size = lowmem_adj_size;
	if (lowmem_minfree_size < array_size)
		array_size = lowmem_minfree_size;
	for (i = 0; i < array_size; i++) {             <span style="white-space:pre">		</span>//根据当前内存与lowmem_minfree数组进行评判,找到lowmem_adj基准值赋给min_score_adj;
		if (other_free < lowmem_minfree[i] &&
		    other_file < lowmem_minfree[i]) {
			min_score_adj = lowmem_adj[i];
			break;
		}
	}
	if (sc->nr_to_scan > 0)
		lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %d\n",
				sc->nr_to_scan, sc->gfp_mask, other_free,
				other_file, min_score_adj);
	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);
	if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
		lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n",
			     sc->nr_to_scan, sc->gfp_mask, rem);
		return rem;
	}
	selected_oom_score_adj = min_score_adj;

	rcu_read_lock();
	for_each_process(tsk) {<span style="white-space:pre">					</span>//该for循环找出oom_score_adj值最大的进程作为目标进程(将被kill),如果最大<span style="font-family: Arial, Helvetica, sans-serif;">oom_score_adj值有多个进程,那么选取rss值最大的进程为目标进程;</span>
		struct task_struct *p;
		int oom_score_adj;

		if (tsk->flags & PF_KTHREAD)
			continue;

		p = find_lock_task_mm(tsk);
		if (!p)
			continue;

		if (test_tsk_thread_flag(p, TIF_MEMDIE) &&
		    time_before_eq(jiffies, lowmem_deathpending_timeout)) {
			task_unlock(p);
			rcu_read_unlock();
			return 0;
		}
		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);
		task_unlock(p);
		if (tasksize <= 0)
			continue;
		if (selected) {
			if (oom_score_adj < selected_oom_score_adj)
				continue;
			if (oom_score_adj == selected_oom_score_adj &&
			    tasksize <= selected_tasksize)
				continue;
		}
		selected = p;
		selected_tasksize = tasksize;
		selected_oom_score_adj = oom_score_adj;
		lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
			     p->pid, p->comm, oom_score_adj, tasksize);
	}
	if (selected) {                        <span style="white-space:pre">	</span>//前面for循环找到一个目标进程,那么便调用send_sig()干掉它。
		lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
			     selected->pid, selected->comm,
			     selected_oom_score_adj, selected_tasksize);
		lowmem_deathpending_timeout = jiffies + HZ;
		send_sig(SIGKILL, selected, 0);
		set_tsk_thread_flag(selected, TIF_MEMDIE);
		rem -= selected_tasksize;
	}
	lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
		     sc->nr_to_scan, sc->gfp_mask, rem);
	rcu_read_unlock();
	return rem;
}
该函数的逻辑很简单,就是kill掉Oomadj值大的进程来回收内存。

注意:由于native进程的Oomadj值为-17,SystemServer进程的Oomadj值为-16,毫无疑问native进程不会被Lowmemorykiller干掉。


第三部分:Oomadj的计算

待续。




Lowmemorykiller笔记

标签:

原文地址:http://blog.csdn.net/guoqifa29/article/details/45370561

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!