2.2 Linux页面回收
Linux中页面回收主要通过两种方式触发:一种是由“内存严重不足”事件触发;另一种是由后台进程kswapd触发,该进程周期性地运行,一旦检测到内存不足,就会触发页面回收操作。这里主要介绍shrink_zone()函数,此函数是Linux操作系统实现页面回收的最核心的函数之一,它实现了对一个内存区域的页面进行回收的功能。该函数主要做了两件事:
① 将某些页面从active链表移到inactive链表,这是由函数shrink_active_list()实现的;
② 从inactive链表中选定一定数目的页面,将其放到一个临时链表中,这由函数shrink_inactive_list()完成。
该函数最终会调用shrink_page_list()去回收这些页面。
2.3 OOMKiller机制
OOM(Out of Memory)是标准Linux内核(kernel)的一种内存管理机制,当系统内存耗尽时,OOM会选择性的杀掉一些进程以求释放一些内存。
Linux在2.6.36内核中修正了OOMKiller的行为,跟之前的OOMKiller相比,主要体现在3个方面:第一,将物理内存页面的使用作为基准而不是虚拟地址空间的大小;第二,导出用户策略的控制权;第三,内核有了一个简单而合理的默认策略。
Linux下有3种Overcommit的策略:0,启发式策略;1,永远允许Overcommit,这种策略适合那些不能承受内存分配失败的应用;2,永远禁止Overcommit,这种策略下系统所能分配的内存不会超过swap+RAM*系数。在Linux系统中,只要存在Overcommit,就可能会有OOMKiller跳出来。当OOMKiller跳出来的时候,期望它可以杀掉没用的且耗内存多的程序,这就需要一个选择目标的策略。Linux下这个选择目标的策略也在随着内核的改进不断的演化。在Linux下每个进程都会有个OOM权重,在/proc/ /oom_adj中,取值是-17~+15,取值越高,越容易被杀掉。用户可以通过设置这些值来影响OOMKiller作出决策。这个值是系统综合进程的内存消耗量、CPU时间、存活时间和oom_adj计算出的,消耗内存越多分值就会越高。除此之外,Linux在计算进程的内存消耗的时候,会将子进程所耗内存的一半同时算到父进程中。
3 Android的低内存管理
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所告知的优先级,强制退出优先级低的应用程序
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) | Powered by Discuz! 7.0.0 |