Android系统的内存管理研究
3Android的低内存管理
Android是一个多任务系统,当启动一个程序时会消耗一定的时间。为了加快运行速度,当退出一个程序时,Android并不会立即杀掉它,这样当用户重新运行该程序时,可以很快地启动。但随着系统中保留的程序越来越多,内存肯定会出现不足,此时就有了Android的低内存管理(Low Memory Killer)机制。
3.1 Low Memory Killer机制
Low Memory Killer是在标准Linux kernel的OOM基础上修改而来的一种内存管理机制,基于oom_adj和占用内存的大小来选择Bad进程。对应于每个oom_adj都有一个空闲内存的阈值,Android kernel每隔一段时间会检查当前空闲内存是否低于某个阈值。如果是,则杀死oom_adj最大的Bad进程。如有两个以上的Bad进程oom_adj相同,则杀死其中占用内存最多的进程。
3.2 Low Memory Killer的实现
Low Memory Killer是以内核驱动的形式实现的,该实现位于drivers/misc/lowmemorykiller.c中,通过注册Cache Shrinker实现。Cache Shrinker是标准Linux kernel回收页面的一种机制,它由内核线程kswapd监控,当空闲内存页面不足时,kswapd会调用注册的Shrinker回调函数,来回收内存页面。lowmem_shrink是这个驱动的核心实现,当内存不足时就会调用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,2*1024,4*1024,16*1024};
lowmem_minfree保存空闲内存的阈值,单位是一个页面4 KB,lowmem_adj保存每个阈值对应的优先级。lowmem_shrink首先计算当前空闲内存的大小,如果小于某个阈值,则以该阈值对应的优先级为基准,遍历各个进程,计算每个进程占用内存的大小,找出优先级大于基准优先级的进程,在这些进程中选择优先级最大的杀死。如果优先级相同,则选择占用内存最多的进程。lowmem_shrink杀死进程的方法是向进程发送一个不可以忽略或阻塞的SIGKILL信号:force_sig(SIGKILL,selected)。
3.3 内存管理
Android中的内存管理分为两个部分:第一部分是当应用程序关闭后,后台对应的进程并没有真正退出,以便下次再启动时能够快速启动;第二部分是当系统内存不够时,Ams会主动根据内存管理机制退出优先级较低的进程。这里主要介绍第二部分。
Ams(Activity manager service)运行在Java环境中,而Android采用Dalvik虚拟机,应用程序和Ams运行在两个独立的虚拟机中,Ams并不会知道应用程序的内存分配情况。那内存是怎么管理的呢?在Android中运行一个Low Memory Killer进程,该进程启动时会首先在Linux内核中把自己注册为一个OOM Killer,即当Linux内核的内存管理模块检测到系统内存低的时候就会通知已经注册的OOM进程,然后这些OOM Killer就可以根据各种规则进行内存释放。当内存满足低的条件时,Linux内核管理模块通知OOM Killer,Killer则根据Ams所告知的优先级,强制退出优先级低的应用程序。
4 Android内存优化研究
Android内存管理机制主要是针对进程的优先级和内存占用情况来对进程进行管理的,所以对内存管理的优化也主要体现在对进程阈值的设定上。
4.1 Android进程
Android根据进程的重要性,将进程分为以下几类:
① FOREGROUD_APP(前台进程),用户正在使用的进程和一些系统进程。
② VISIBLE_APP(可见的进程)跟FOREGROUD_APP类似,用户正在使用或看得到,它们的区别就是VISIBLE_APP可能不是用户关注的程序,但是用户看得到,或者没有覆盖到整个屏幕,只有屏幕的一部分。
③ SECONDARY_SERVER(后台进程)是被切换到后台的进程,后台进程的管理策略有很多种,Android采用一种消极的方式,即尽可能地保留后台程序,这样可以很好地提高再次启动的速度。
④ HIDDEN_APP(隐藏的程序)是用户看不见但是还在运行的程序,跟②有一定的区别。
⑤ CONTENT_PROVIDER(内容供应节点)没有程序实体,仅提供内容供别的进程使用,比如日历供应节点、邮件供应节点等。
⑥ EMPTY_APP(空进程)既不提供服务,也不提供内容。当进程退出时,系统会自动为其保留一个空进程,目的也是为了保证程序再次启动的速度。
以上每个进程都会有个oom_adj值,①~⑥分别为0、1、2、7、14、15。
除了程序的重要性,Android系统还会维护另外一张表,进程优先级及阈值对应关系如表1所列。
表1 进程优先级及阈值对应关系
这个表定义了一个对应关系,每个警戒值对应了一个重要性值,当系统的可用内存低于某个警戒值时,就杀掉所有大于该警戒值对应的重要性的程序。
4.2 内存管理优化
Android的Low Memory Killer机制基本上可以满足普通用户的需求,但是针对于某些特定用户就需要对特定程序进行某些设置,从而手动地参与内存管理。对进程的优化主要设置6类进程的阈值,系统阈值存在的问题包括:第一,各类进程管理策略的阈值相当接近,在实际程序运行中,很容易导致多种类型的进程同时被关闭;第二,阈值上限较低,一般手机启动后,可用内存在50~100 MB左右,但随着手机的使用,内存会逐渐减小,最后降低到24 MB左右,但24 MB相对较低,会降低系统的反应速度。
优化原则:拉开各进程的阈值层次,使得进程管理机制能更有效地工作;提高阈值上限,空出更多的空余内存,以提升系统整体的运行速度;前台进程、可见进程和次要服务是与用户体验息息相关的内容,这部分的进程管理策略要相对保守,给这些进程留下足够的运行空间;压榨无用进程,腾出内存空间给主要程序使用。
4.3 内存测试
本文以OK6410开发板为例,对内存优化进行测试,OK6410采用的是Android2.3.4系统,256 MB内存。系统默认内存配置如图1所示。
图1 系统默认内存配置(MB)
这里采用测试程序对系统性能进行测试评分,在系统默认配置情况下优化前的内存测评如图2所示。
图2 优化前的内存测评
图3 优化内存分配(MB)
针对某些特定需求,以游戏玩家为例,此时只需要游戏运行有足够的内存空间,而对多任务的需求不高。因此,可以尽量压榨后台进程、内容供应节点和空进程,将内存尽可能地留给前台进程和系统程序,进而提升游戏运行速度。在此设置的值如图3所示。
此设置大幅度提升了后台进程、内容供应节点和空进程的阈值,这样当系统内存小于100 MB时就可以最先杀死空进程,然后根据内存情况,进而杀死后台进程和内容供应节点。如此,就为前台进程和系统进程留下了足够的内存空间,很好地满足特定用户的需求。在此情况下的系统测评如图4所示。
图4 优化后测评分数
通过图2跟图4的分数以及理论分析,可以发现系统在内存方面的性能有了明显的提升。
- Linux内存使用的体会 (04-23)
- 嵌入式操作系统uCLinux详解(03-19)
- Symbian与WinCE内存管理技术分析及比较(06-19)
- μC/OS-Ⅱ实时操作系统内存管理的改进(04-10)
- 动态内存管理在面向嵌入式实时系统中的研究(06-28)
- 记录仪实时多任务调度策略的研究(07-16)