当前位置: 代码迷 >> 综合 >> Android内存管理机制之一:low memory killer
  详细解决方案

Android内存管理机制之一:low memory killer

热度:25   发布时间:2024-01-10 00:02:19.0

(1)Android是一个多任务系统,也就是说可以同时运行多个程序,这个大家应该很熟悉。一般来说,启动运行一个程序是有一定的时间开销的,因 此为了加快运行速度,当你退出一个程序时,Android并不会立即杀掉它,这样下次再运行该程序时,可以很快的启动。随着系统中保留的程序越来越多,内 存肯定会出现不足,这个时候Android系统开始挥舞屠刀杀程序。这里就有一个很明显的问题,杀谁?

(2)Android系统中杀程序 的这个刽子手被称作"LowMemory Killer",它是在Linux内核中实现的。这里它实现了一个机制,由程序的重要性来决定杀谁。通俗来说,谁不干活,先杀谁。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值,这个值越小,程序越重要,被杀的可能性越低。

(3)除了上述程序重要性分类之外,Android系统还维护着另外一张表,这张表是一个对应关系,以N1为例:

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

这个表是定义了一个对应关系,每一个警戒值对应了一个重要性值,当系统的可用内存低于某个警戒值时,就杀掉所有大于该警戒值对应的重要性值的程序。 比如说,当可用内存小于6144 * 4K = 24MB时,开始杀所有的EMPTY_APP,当可用内存小于5632 * 4K = 22MB时,开始杀所有
的CONTENT_PROVIDER和EMPTY_APP。


(4) alter minfree改的是什么呢,上面这张对应表是由两个文件组成的:
/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree。

alter minfreee就是修改/sys/module/lowmemorykiller/parameters/minfree这个文件的,举例来说,如果把最后一项改为32 * 1024,那么当可用内存小于128MB是,就开始杀所有的EMPTY_APP。


Android Low Memory Killer介绍
基本原理:

Android的Low Memory Killer是在标准linux kernel的OOM基础上修改而来的一种内存管理机制,当系统内存不足时,杀死Bad进程释放其内存。Bad进程的选择标准有两个:oom_adj和占用内存的大小。oom_adj代表进程的优先级,数值越大,优先级越高,对应每个oom_adj都有一个空闲内存的阈值。Android Kernel每隔一段时间会检查当前空闲内存是否低于某个阈值,如果是,则杀死oom_adj最大的Bad进程,如果有两个以上Bad进程oom_adj相同,则杀死其中占用内存最多的进程。  

Low Memory Killer与OOM的区别

OOM即Out of Memory是标准linux Kernel的一种内存管理机制,Low Memory Killer在它基础上作了改进:

OOM基于多个标准给每个进程打分,分最高的进程将被杀死;Low MemoryKiller则用oom_adj和占用内存的大小来选择Bad进程,OOM在内存分配不足时调用,而Low Memory Killer每隔一段时间就会检查,一旦发现空闲内存低于某个阈值,则杀死Bad进程。

Low Memory Killer的实现

Low Memory Killer的源代码在drivers/staging/Android/lowmemorykiller.c中,它是通过注册Cache Shrinker来实现的。Cache Shrinker是标准linux kernel回收内存页面的一种机制,它由内核线程kswapd监控,当空闲内存页面不足时,kswapd会调用注册的Shrinker回调函数,来回收内存页面。

Low Memory Killer是在模块初始化时注册Cache Shrinker的,代码如下:

static int__init lowmem_init(void)

{

register_shrinker(&lowmem_shrinker);//注册Cache Shrinker

return 0;

}

lowmem_shrinker的定义如下:

static struct shrinker lowmem_shrinker=

{

.shrink=lowmem_shrink,

.seeks=DEFAULT_SEEKS*16

};

register_shrinker会将lowmem_shrink加入Shrinker List中,被kswapd在遍历Shrinker List时调用,而Low Memory Killer的功能就是在lowmem_shrink中实现的。

lowmem_shrink用两个数组作为选择Bad进程的依据,这两个数组的定义如下:

static int lowmem_adj[6]=

{

0,

1,

6,

12,

};

static int lowmem_adj_size=4;

static size_t lowmem_minfree[6]={

3*512,//6MB

2*1024,//8MB

4*1024,//16MB

16*1024,//64MB

};

lowmem_minfree保存空闲内存的阈值,单位是一个页面4K,lowmem_adj保存每个阈值对应的优先级。lowmem_shrink首先计算当前空闲内存的大小,如果小于某个阈值,则以该阈值对应的优先级为基准,遍历各个进程,计算每个进程占用内存的大小,找出优先级大于基准优先级的进程,在这些进程中选择优先级最大的杀死,如果优先级相同,则选择占用内存最多的进程。

lowmem_shrink杀死进程的方法是向进程发送一个不可以忽略或阻塞的SIGKILL信号:

force_sig(SIGKILL,selected);



用户接口

设置空闲内存阈值的接口:/sys/module/lowmemorykiller/parameters/minfree,设置对应优先级的接口:/sys/module/lowmemorykiller/parameters/adj,设置各个进程优先级的接口:/proc/<进程pid>/oom_adj。

Android启动时读取的配置文件/init.rc中定义了相应的属性供AP使用并有设置这些参数:

#killed by the kernel.These are used in

ActivityManagerService.

setprop ro.FOREGROUND_APP_ADJ 0

setprop ro.VISIBLE_APP_ADJ 1

setprop ro.SECONDARY_SERVER_ADJ 2

setprop ro.BACKUP_APP_ADJ 2

setprop ro.HOME_APP_ADJ 4

setprop ro.HIDDEN_APP_MIN_ADJ 7

setprop ro.CONTENT_PROVIDER_ADJ 14

setprop ro.EMPTY_APP_ADJ 15

#Define the memory thresholds at which the above process

classes will

#be killed.These numbers are in pages(4k).

setprop ro.FOREGROUND_APP_MEM 1536

setprop ro.VISIBLE_APP_MEM 2048

setprop ro.SECONDARY_SERVER_MEM 4096

setprop ro.BACKUP_APP_MEM 4096

setprop ro.HOME_APP_MEM 4096

setprop ro.HIDDEN_APP_MEM 5120

setprop ro.CONTENT_PROVIDER_MEM 5632

setprop ro.EMPTY_APP_MEM 6144

#Write value must be consistent with the above properties.

#Note that the driver only supports 6 slots,so we have HOME_APP

at the

#same memory level as services.

write/sys/module/lowmemorykiller/parameters/adj

0,1,2,7,14,15

write/sys/module/lowmemorykiller/parameters/minfree

1536,2048,4096,5120,5632,6144

#Set init its forked children's oom_adj.

write/proc/1/oom_adj-16

从以上设置可以看出,将init进程oom_adj设置为-16,从而保证init进程永远不会被杀掉

  相关解决方案