深挖android low memory killer
对于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相关推荐
- Android low memory killer 机制
Android中,进程的生命周期都是由系统控制的.即使用户在界面上关掉一个应用,切换到了别的应用,那个应用的进程依然是存在于内存之中的.这样设计的目的是为了下次启动应用能更加快速.当然,随着系统运行时 ...
- Android Low memory killer by 永远的伊苏
Android中,进程的生命周期都是由系统控制的,即使用户关掉了程序,进程依然是存在于内存之中.这样设计的目的是为了下次能快速启动.当然,随着系统运行时间的增长,内存会越来越少.Android Ker ...
- Android进程优先级architecture : low memory killer (/system/core/lmkd/lmkd.c)
更新 ActivityManagerService.updateOomAdjLocked 保存 /proc/pid/oom_adj /proc/pid/oom_score_adj /proc/pid/ ...
- android的oomkiller_Android Low memory killer
Android Low memory killer by 永远的伊苏 Android中,进程的生命周期都是由系统控制的,即使用户关掉了程序,进程依然是存在于内存之中.这样设计的目的是为了下次能快速启动 ...
- 【Android 进程保活】Low Memory Killer 机制
文章目录 一.Low Memory Killer 机制 二.Low Memory Killer 参数 一.Low Memory Killer 机制 Android 中有一套 Low Memory Ki ...
- linux内核如何修改lowmem,技术内幕:Android对Linux内核的增强 Low Memory Killer
6 09 2013 技术内幕:Android对Linux内核的增强 Low Memory Killer Low Memory Killer(低内存管理) 对于PC来说,内存是 至关重要.如果某个程序发 ...
- android app打开另一个app并触发按钮_Android进程调度:Low memory killer(4)修改版
相关源码文件:framework/base/service/core/java/com/android/server/am/ActiveServices.javaframework/base/serv ...
- android lmk机制,android LMK(low memory killer) 工作机制
Android Kernel 会定时执行一次检查,杀死一些进程,释放掉内存. 那么,如何来判断,那些进程是需要杀死的呢?答案就是我们的标题:Low memory killer机制. Low memor ...
- android 杀死进程回收资源,Android之进程回收机制LMK(Low Memory Killer)
熟悉Android系统的童鞋都知道,系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来.打开的应用越多,后台缓存的进程也越多.在系统内存不足的情况下,系 ...
最新文章
- SpringBoot开发案例之整合Dubbo分布式服务
- 团队项目第二阶段冲刺站立会议06
- php什么框架性能高,主流PHP框架性能比较
- strlen()函数 与 “\0“ 的关系 与 利用;strcmp()
- Altium Designer中敷铜间距修改问题
- c# 中文字符(全角、半角)通用处理
- 压力测试和负载测试区别_如何理解与区分软件性能测试、负载测试、稳定性测试、压力测试...
- 新买的内置光驱读取光盘有杂音的解决办法
- 高品质UI设计模板PSD下载,设计师的最佳临摹素材
- httpClient中的三种超时时间设置
- Mysql控制流语句
- 你要好好的---歌词
- dnf助手服务器内部出错,地下城与勇士TGP的DNF助手异常解决办法 TGP-DNF助手补丁不适配怎么办...
- 杰奇2.3内核淡绿唯美小说网站源码 PC+手机版
- 神经网络——深度学习应用于计算机视觉
- MRI_Made_Easy 磁共振成像原理-物理基础4
- 打印图片一直显示连接传真服务器,打印机打印时显示传真怎么办
- 5.17 图层面板的使用 [原创Ps教程]
- 记录日记软件哪个好用
- jsp_servlet【基础】
热门文章
- 跑步呼吸方法(细胞分裂呼吸法)
- java智能提示_【Java】智能提示的设置
- kali2 安装docker_kali linux 安装docker
- redis的hash类型
- 各层电子数排布规则_干货 | 高中化学电子排布、第一电离能和电负性知识汇总...
- java stream 使用局部变量
- apscheduler Trigger
- 19 Signals and Signal Handling
- TensorFlow Attention
- 输变电设备物联网节点设备无线组网协议_AIS-Link-艾森智能的工业物联网连接协议...