Chinaunix首页 | 论坛 | 博客
  • 博客访问: 365902
  • 博文数量: 242
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 1134
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-20 10:53
文章分类

全部博文(242)

文章存档

2015年(1)

2014年(10)

2013年(18)

2012年(213)

分类:

2012-11-09 16:33:21

原文地址:Android low memory killer 详解 作者:tuyer

Android在内存管理上与linux有些小的区别。其中一个就是引入了Low memory killer .

1,引入原因

   Android是一个多任务系统,也就是说可以同时运行多个程序,这个大家应该很熟悉。一般来说,启动运行一个程序是有一定的时间开销的,因此为了加快运行速度,当你退出一个程序时,Android并不会立即杀掉它,这样下次再运行该程序时,可以很快的启动。随着系统中保留的程序越来越多,内存肯定会出现不足,low memory killer就是在系统内存低于某值时,清除相关的程序,保障系统保持拥有一定数量的空闲内存。
2,基本原理和重要概念

   Low memory killer根据两个原则,进程的重要性和释放这个进程可获取的空闲内存数量,来决定释放的进程。

(1)进程的重要性,由task_struct->signal_struct->oom_adj决定。

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值,这个值越小,程序越重要,被杀的可能性越低。

(2)进程的内存,通过get_mm_rss获取,在相同的oom_adj下,内存大的,优先被杀。

(3)那内存低到什么情况下,low memory killer开始干活呢?Android提供了两个数组,一个lowmem_adj,一个lowmem_minfree。前者存放着oom_adj的阀值,后者存放着minfree的警戒值,以page为单位(4K)。

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

3,源码解析

    module_init(lowmem_init);
    module_exit(lowmem_exit);

    模块加载和退出的函数,主要的功能就是register_shrinker和unregister_shrinker结构体lowmem_shrinker。主要是将函数lowmem_shrink注册到shrinker链表里,在mm_scan调用。

    下面详细的介绍这个函数:

    for (i = 0; i < array_size; i++) {
        if (other_file < lowmem_minfree[i]) {
            min_adj = lowmem_adj[i];
            break;
        }
    }

    other_file,系统的空闲内存数,根据上面的逻辑判断出,low memory killer需要对adj高于多少(min_adj)的进程进行分析是否释放。

       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;
    }

     判断,系统当前的状态是否需要进行low memory killer。

for_each_process(p) {
        struct mm_struct *mm;
        struct signal_struct *sig;
        int oom_adj;

        task_lock(p);
        mm = p->mm;
        sig = p->signal;
        if (!mm || !sig) {
            task_unlock(p);
            continue;
        }
        oom_adj = sig->oom_adj;
        if (oom_adj < min_adj) {
            task_unlock(p);
            continue;
        }
        tasksize = get_mm_rss(mm);
        task_unlock(p);
        if (tasksize <= 0)
            continue;
        if (selected) {
            if (oom_adj < selected_oom_adj)
                continue;
            if (oom_adj == selected_oom_adj &&
                tasksize <= selected_tasksize)
                continue;
        }
        selected = p;
        selected_tasksize = tasksize;
        selected_oom_adj = oom_adj;
        lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
                 p->pid, p->comm, oom_adj, tasksize);
    }

   对每个sig->oom_adj大于min_adj的进程,找到占用内存最大的进程存放在selected中。

if (selected) {
        if (fatal_signal_pending(selected)) {
            pr_warning("process %d is suffering a slow death\n",
                   selected->pid);
            read_unlock(&tasklist_lock);
            return rem;
        }
        lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
                 selected->pid, selected->comm,
                 selected_oom_adj, selected_tasksize);
        force_sig(SIGKILL, selected);
        rem -= selected_tasksize;
    }

   发送SIGKILL信息,杀掉该进程。

4,配置

   通过下面两个文件,/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller /parameters/minfree配置系统的相关参数。


Linux操作系统的传统理念就是内存用的越多越好,尽可能拿来用,既然被尽量的使用,自然应该有清除机制。以Linux为基础,自然部分继承了这个特性。Android使用lowmemorykiller在达到某个内存门限的情况下去选择进程删除来释放内存。关键的配置文件有如下两个,/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree配置系统的相关参数。


adj文件包含队列包含oomadj队列,当对应的minfree值达到,则进程的oomadj如果大于这个值将被杀掉。

minfree包含对应oom_adj的警戒值。

参考如下:
oom_adj     内存警戒值( 以4K为单位)
0             1536
1             2048
2             4096
7             5120
14             5632
15             6144
一般情况下,默认设置在system/core/rootdir/init.rc中
# Define the oom_adj values for the classes of processes that can be
# 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

实际上在frameworks/base/services/java/com//server/am/ActivityManagerService.java中定义了两个更高的优先级。
// This is a process running a core server, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
static final int CORE_SERVER_ADJ = -12;

// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -16;

根据以上分析,对于某些小内存设备,我们可以调整对应的门限值,例如:
一般调整后三个值。
echo "1536,2048,4096,15360,17920,20480">/sys/module/lowmemorykiller/parameters/minfree

阅读(417) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~