Android在内存管理上与linux有些小的区别。其中一个就是引入了Low memory killer .

1,引入原因

Android是一个多任务系统,也就是说可以同时运行多个程序,这个大家应该很熟悉。一般来说,启动运行一个程序是有一定的时间开销的,因此为了加快运行速度,当你退出一个程序时,Android并不会立即杀掉它,这样下次再运行该程序时,可以很快的启动。随着系统中保留的程序越来越多,内存肯定会出现不足,low memory killer就是在系统内存低于某值时,清除相关的程序,保障系统保持拥有一定数量的空闲内存。

2,基本原理和重要概念

Low memory killer根据两个原则,进程的重要性和释放这个进程可获取的空闲内存数量,来决定释放的进程。

(1)进程的重要性,由task_struct->signal_struct->oom_adj决定。

Android将程序分成以下几类,按照重要性依次降低的顺序:

名称 oom_adj 解释
FOREGROUD_APP 0 前台程序,可以理解为你正在使用的程序
VISIBLE_APP 1 用户可见的程序
SECONDARY_SERVER 2 后台服务,比如说QQ会在后台运行服务
HOME_APP 4 HOME,就是主界面
HIDDEN_APP 7 被隐藏的程序
CONTENT_PROVIDER 14 内容提供者,
EMPTY_APP 15 空程序,既不提供服务,也不提供内容


其中每个程序都会有一个oom_adj值,这个值越小,程序越重要,被杀的可能性越低。

(2)进程的内存,通过get_mm_rss获取,在相同的oom_adj下,内存大的,优先被杀。

(3)那内存低到什么情况下,low memory killer开始干活呢?Android提供了两个数组,一个lowmem_adj,一个lowmem_minfree。前者存放着oom_adj的阀值,后者存放着minfree的警戒值,以page为单位(4K)。

oom_adj 内存警戒值( 以4K为单位)
0 1536
1 2048
2 4096
7 5120
14 5632
15 6144

3,源码解析

module_init(lowmem_init);
module_exit(lowmem_exit);

模块加载和退出的函数,主要的功能就是register_shrinker和unregister_shrinker结构体lowmem_shrinker。主要是将函数lowmem_shrink注册到shrinker链表里,在mm_scan调用。

下面详细的介绍这个函数:

for (i = 0; i < array_size; i++) {
if (other_file < lowmem_minfree[i]) {
min_adj = lowmem_adj[i];
break;
}
}

other_file,系统的空闲内存数,根据上面的逻辑判断出,low memory killer需要对adj高于多少(min_adj)的进程进行分析是否释放。

if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) {
lowmem_print(5, "lowmem_shrink %d, %x, return %d/n",
nr_to_scan, gfp_mask, rem);
return rem;
}

判断,系统当前的状态是否需要进行low memory killer。

for_each_process(p) {
struct mm_struct *mm;
struct signal_struct *sig;
int oom_adj;

task_lock(p);
mm = p->mm;
sig = p->signal;
if (!mm || !sig) {
task_unlock(p);
continue;
}
oom_adj = sig->oom_adj;
if (oom_adj < min_adj) {
task_unlock(p);
continue;
}
tasksize = get_mm_rss(mm);
task_unlock(p);
if (tasksize <= 0)
continue;
if (selected) {
if (oom_adj < selected_oom_adj)
continue;
if (oom_adj == selected_oom_adj &&
tasksize <= selected_tasksize)
continue;
}
selected = p;
selected_tasksize = tasksize;
selected_oom_adj = oom_adj;
lowmem_print(2, "select %d (%s), adj %d, size %d, to kill/n",
p->pid, p->comm, oom_adj, tasksize);
}

对每个sig->oom_adj大于min_adj的进程,找到占用内存最大的进程存放在selected中。

if (selected) {
if (fatal_signal_pending(selected)) {
pr_warning("process %d is suffering a slow death/n",
selected->pid);
read_unlock(&tasklist_lock);
return rem;
}
lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d/n",
selected->pid, selected->comm,
selected_oom_adj, selected_tasksize);
force_sig(SIGKILL, selected);
rem -= selected_tasksize;
}

发送SIGKILL信息,杀掉该进程。

4,配置

通过下面两个文件,/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree配置系统的相关参数。



来自http://blog.chinaunix.net/space.php?uid=9185047&do=blog&id=445192

更多相关文章

  1. 最新历史版本 :浅析Android线程模型
  2. Android应用启动后自动创建桌面快捷方式
  3. Android为每个应用程序分配的内存大小是多少
  4. Android实战技巧之四十四:Hello,Native!
  5. 想抢先体验Android操作系统的魅力吗?那就使用Android(安卓)LiveCD
  6. Android(安卓)系统基础
  7. Android(安卓)内存泄漏调试
  8. Mac下配置Android(安卓)NDK环境并搭建Cocos2d-x环境并Eclipse正
  9. Android基础和运行机制

随机推荐

  1. 终于搞清楚正态分布、指数分布到底是啥了
  2. Ansible 之 ansible的模块使用帮助
  3. Apache Flink漏洞复现
  4. Ansible 之 ansible的模块使用
  5. Python数据可视化:2018年电影分析
  6. 2.21 使用vSphere Client管理VMware ESXi
  7. 能把统计学的原理和应用说明白,这本书不简
  8. 教你做超惊艳的南丁格尔玫瑰图
  9. SQL今日一题(19):表复用
  10. 18个常见的数据分析面试题-概率统计类