对于PC来说,内存是至关重要。如果某个程序发生了内存泄漏,那么一般情况下系统就会将其进程Kill掉。Linux中使用一种名称为OOM(Out Of Memory,内存不足)的机制来完成这个任务,该机制会在系统内存不足的情况下,选择一个进程并将其Kill掉。Android由于是嵌入式设备的操作系统,则使用了一个新的机制Low Memory Killer来完成同样的任务。下面首先来看看Low Memory Killer机制的原理以及它是如何选择被Kill的进程的。

  1.Low Memory Killer的原理和机制

  Low Memory Killer在用户空间中指定了一组内存临界值,当其中的某个值与进程描述中的oom_adj值在同一范围时,该进程将被Kill掉。通常,在“/sys/module/lowmemorykiller / parameters/adj”中指定oom_adj的最小值,在“/sys/module/lowmemorykiller/parameters/minfree”中储存空闲页面的数量,所有的值都用一个逗号将其隔开且以升序排列。比如:把“0,8”写入到/sys/module/lowmemorykiller/parameters/adj中,把“1024,4096”写入到/sys/module/lowmemory- killer/parameters/minfree中,就表示当一个进程的空闲存储空间下降到4096个页面时,oom_adj值为8或者更大的进程会被Kill掉。同理,当一个进程的空闲存储空间下降到1024个页面时,oom_adj值为0或者更大的进程会被Kill掉。我们发现在lowmemorykiller.c中就指定了这样的值,如下所示:

static int lowmem_adj[6] = {0,1,6,12,
};
static int lowmem_adj_size = 4;
static size_t lowmem_minfree[6] = {3*512, // 6MB2*1024, // 8MB4*1024, // 16MB16*1024, // 64MB
};
static int lowmem_minfree_size = 4;

这就说明,当一个进程的空闲空间下降到3´512个页面时,oom_adj值为0或者更大的进程会被Kill掉;当一个进程的空闲空间下降到2´1024个页面时,oom_adj值为10或者更大的进程会被Kill掉,依此类推。其实更简明的理解就是满足以下条件的进程将被优先Kill掉:

  task_struct->signal_struct->oom_adj越大的越优先被Kill。

  占用物理内存最多的那个进程会被优先Kill。

  进程描述符中的signal_struct->oom_adj表示当内存短缺时进程被选择并Kill的优先级,取值范围是-17~15。如果是-17,则表示不会被选中,值越大越可能被选中。当某个进程被选中后,内核会发送SIGKILL信号将其Kill掉。

  实际上,Low Memory Killer驱动程序会认为被用于缓存的存储空间都要被释放,但是,如果很大一部分缓存存储空间处于被锁定的状态,那么这将是一个非常严重的错误,并且当正常的oom killer被触发之前,进程是不会被Kill掉的。

2.Low Memory Killer的具体实现

在了解了Low Memory Killer的原理之后,我们再来看如何实现这个驱动。Low Memory Killer驱动的实现位于drivers/misc/lowmemorykiller.c。

该驱动的实现非常简单,其初始化与退出操作也是我们到目前为止见过的最简单的,代码如下:

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);
module_exit(lowmem_exit);

  在初始化函数lowmem_init中通过register_shrinker注册了一个shrinker为lowmem_shrinker;退出时又调用了函数lowmem_exit,通过unregister_shrinker来卸载被注册的lowmem_shrinker。其中lowmem_shrinker的定义如下:

static struct shrinker lowmem_shrinker = {.shrink = lowmem_shrink,.seeks = DEFAULT_SEEKS * 16
};

 lowmem_shrink是这个驱动的核心实现,当内存不足时就会调用lowmem_shrink方法来Kill掉某些进程。下面来分析其具体实现,实现代码如下:

static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
{struct task_struct *p;struct task_struct *selected = NULL;int rem = 0;int tasksize;int i;int min_adj = OOM_ADJUST_MAX + 1;int selected_tasksize = 0;int array_size = ARRAY_SIZE(lowmem_adj);int other_free = global_page_state(NR_FREE_PAGES);int other_file = global_page_state(NR_FILE_PAGES);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++) {if (other_free < lowmem_minfree[i] &&other_file < lowmem_minfree[i]) {min_adj = lowmem_adj[i];break;}}if(nr_to_scan > 0)lowmem_print(3, "lowmem_shrink %d, %x, ofree %d %d, ma %d\n", nr_to_scan, gfp_mask, other_free, other_file, min_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 (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;}read_lock(&tasklist_lock);for_each_process(p) {if (p->oomkilladj < min_adj || !p->mm)continue;tasksize = get_mm_rss(p->mm);if (tasksize <= 0)continue;if (selected) {if (p->oomkilladj < selected->oomkilladj)continue;if (p->oomkilladj == selected->oomkilladj &&tasksize <= selected_tasksize)continue;}selected = p;selected_tasksize = tasksize;lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",p->pid, p->comm, p->oomkilladj, tasksize);}if(selected != NULL) {lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",selected->pid, selected->comm,selected->oomkilladj, selected_tasksize);force_sig(SIGKILL, selected);rem -= selected_tasksize;}lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem);read_unlock(&tasklist_lock);return rem;
}

可以看出,其中多处用到了global_page_state函数。有很多人找不到这个函数,其实它被定义在了linux/vmstat.h中,其参数使用zone_stat_item枚举,被定义在linux/mmzone.h中,具体代码如下:

enum zone_stat_item {NR_FREE_PAGES,NR_LRU_BASE,NR_INACTIVE_ANON = NR_LRU_BASE,NR_ACTIVE_ANON,NR_INACTIVE_FILE,NR_ACTIVE_FILE,
#ifdef CONFIG_UNEVICTABLE_LRUNR_UNEVICTABLE,NR_MLOCK,
#elseNR_UNEVICTABLE = NR_ACTIVE_FILE, /* 避免编译错误*/NR_MLOCK = NR_ACTIVE_FILE,
#endifNR_ANON_PAGES,        /* 匿名映射页面*/NR_FILE_MAPPED,        /*映射页面*/NR_FILE_PAGES,NR_FILE_DIRTY,NR_WRITEBACK,NR_SLAB_RECLAIMABLE,NR_SLAB_UNRECLAIMABLE,NR_PAGETABLE,NR_UNSTABLE_NFS,NR_BOUNCE,NR_VMSCAN_WRITE,NR_WRITEBACK_TEMP,    /* 使用临时缓冲区*/
#ifdef CONFIG_NUMANUMA_HIT,            /* 在预定节点上分配*/NUMA_MISS,            /* 在非预定节点上分配*/NUMA_FOREIGN,NUMA_INTERLEAVE_HIT,NUMA_LOCAL,            /* 从本地页面分配*/NUMA_OTHER,            /* 从其他节点分配 */
#endifNR_VM_ZONE_STAT_ITEMS };

 再回过头来看owmem_shrink函数,首先确定我们所定义的lowmem_adj和lowmem_minfree数组的大小(元素个数)是否一致,如果不一致则以最小的为基准。因为我们需要通过比较lowmem_minfree中的空闲储存空间的值,以确定最小min_adj值(当满足其条件时,通过其数组索引来寻找lowmem_adj中对应元素的值);之后检测min_adj的值是否是初始值“OOM_ADJUST_MAX + 1”,如果是,则表示没有满足条件的min_adj值,否则进入下一步;然后使用循环对每一个进程块进行判断,通过min_adj来寻找满足条件的具体进程(主要包括对oomkilladj和task_struct进行判断);最后,对找到的进程进行NULL判断,通过“force_sig(SIGKILL, selected)”发送一条SIGKILL信号到内核,Kill掉被选中的“selected”进程。

  关于Low Memory Killer的分析就到这里,在了解了其机制和原理之后,我们发现它的实现非常简单,与标准的Linux OOM机制类似,只是实现方式稍有不同。标准Linux的OOM Killer机制在mm/oom_kill.c中实现,且会被__alloc_pages_may_oom调用(在分配内存时,即mm/page_alloc.c中)。oom_kill.c最主要的一个函数是out_of_memory,它选择一个bad进程Kill,Kill的方法同样是通过发送SIGKILL信号。在out_of_memory中通过调用select_bad_process来选择一个进程Kill,选择的依据在badness函数中实现,基于多个标准来给每个进程评分,评分最高的被选中并Kill。一般而言,占用内存越多,oom_adj就越大,也就越有可能被选中。

深挖android low memory killer相关推荐

  1. Android low memory killer 机制

    Android中,进程的生命周期都是由系统控制的.即使用户在界面上关掉一个应用,切换到了别的应用,那个应用的进程依然是存在于内存之中的.这样设计的目的是为了下次启动应用能更加快速.当然,随着系统运行时 ...

  2. Android Low memory killer by 永远的伊苏

    Android中,进程的生命周期都是由系统控制的,即使用户关掉了程序,进程依然是存在于内存之中.这样设计的目的是为了下次能快速启动.当然,随着系统运行时间的增长,内存会越来越少.Android Ker ...

  3. Android进程优先级architecture : low memory killer (/system/core/lmkd/lmkd.c)

    更新 ActivityManagerService.updateOomAdjLocked 保存 /proc/pid/oom_adj /proc/pid/oom_score_adj /proc/pid/ ...

  4. android的oomkiller_Android Low memory killer

    Android Low memory killer by 永远的伊苏 Android中,进程的生命周期都是由系统控制的,即使用户关掉了程序,进程依然是存在于内存之中.这样设计的目的是为了下次能快速启动 ...

  5. 【Android 进程保活】Low Memory Killer 机制

    文章目录 一.Low Memory Killer 机制 二.Low Memory Killer 参数 一.Low Memory Killer 机制 Android 中有一套 Low Memory Ki ...

  6. linux内核如何修改lowmem,技术内幕:Android对Linux内核的增强 Low Memory Killer

    6 09 2013 技术内幕:Android对Linux内核的增强 Low Memory Killer Low Memory Killer(低内存管理) 对于PC来说,内存是 至关重要.如果某个程序发 ...

  7. android app打开另一个app并触发按钮_Android进程调度:Low memory killer(4)修改版

    相关源码文件:framework/base/service/core/java/com/android/server/am/ActiveServices.javaframework/base/serv ...

  8. android lmk机制,android LMK(low memory killer) 工作机制

    Android Kernel 会定时执行一次检查,杀死一些进程,释放掉内存. 那么,如何来判断,那些进程是需要杀死的呢?答案就是我们的标题:Low memory killer机制. Low memor ...

  9. android 杀死进程回收资源,Android之进程回收机制LMK(Low Memory Killer)

    熟悉Android系统的童鞋都知道,系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来.打开的应用越多,后台缓存的进程也越多.在系统内存不足的情况下,系 ...

最新文章

  1. SpringBoot开发案例之整合Dubbo分布式服务
  2. 团队项目第二阶段冲刺站立会议06
  3. php什么框架性能高,主流PHP框架性能比较
  4. strlen()函数 与 “\0“ 的关系 与 利用;strcmp()
  5. Altium Designer中敷铜间距修改问题
  6. c# 中文字符(全角、半角)通用处理
  7. 压力测试和负载测试区别_如何理解与区分软件性能测试、负载测试、稳定性测试、压力测试...
  8. 新买的内置光驱读取光盘有杂音的解决办法
  9. 高品质UI设计模板PSD下载,设计师的最佳临摹素材
  10. httpClient中的三种超时时间设置
  11. Mysql控制流语句
  12. 你要好好的---歌词
  13. dnf助手服务器内部出错,地下城与勇士TGP的DNF助手异常解决办法 TGP-DNF助手补丁不适配怎么办...
  14. 杰奇2.3内核淡绿唯美小说网站源码 PC+手机版
  15. 神经网络——深度学习应用于计算机视觉
  16. MRI_Made_Easy 磁共振成像原理-物理基础4
  17. 打印图片一直显示连接传真服务器,打印机打印时显示传真怎么办
  18. 5.17 图层面板的使用 [原创Ps教程]
  19. 记录日记软件哪个好用
  20. jsp_servlet【基础】

热门文章

  1. 跑步呼吸方法(细胞分裂呼吸法)
  2. java智能提示_【Java】智能提示的设置
  3. kali2 安装docker_kali linux 安装docker
  4. redis的hash类型
  5. 各层电子数排布规则_干货 | 高中化学电子排布、第一电离能和电负性知识汇总...
  6. java stream 使用局部变量
  7. apscheduler Trigger
  8. 19 Signals and Signal Handling
  9. TensorFlow Attention
  10. 输变电设备物联网节点设备无线组网协议_AIS-Link-艾森智能的工业物联网连接协议...