Android Low memory killer(上)

本文参照: http://blog.sina.com.cn/s/blog_4d66a3cb0100prfe.html
 Android中,进程的生命周期都是由系统控制的,即使用户关掉了程序,进程依然是存在于内存之中。这样设计的目的是为了下次能快速启动。当然,随着系统运行时间的增长,内存会越来越少。Android Kernel 会定时执行一次检查,杀死一些进程,释放掉内存。
      那么,如何来判断,那些进程是需要杀死的呢?答案就是我们的标题:Low memory killer机制。
    Android 的Low memory killer是基于linux的OOM(out of memory)  规则改进而来的。 OOM通过一些比较复杂的评分机制,对进程进行打分,然后将分数高的进程判定为bad进程,杀死并释放内存。
     Low memory killer 主要是通过进程的oom_adj 来判定进程的重要程度。oom_adj的大小和进程的类型以及进程被调度的次序有关。
     对于 Android4.0以前 Low memory killer  的具体实现可参看: kernel/drivers/misc/lowmemorykiller.c 
    对于 Android4.0后 Low memory killer  的具体实现可参看: common/drivers/staging/lowmemorykiller.c 
     其原理很简单,在linux中,存在一个kswapd的内核线程,当linux回收存放分页的时候,kswapd线程将会遍历一张shrinker链表,并执行回调。shrinker是在中common\include\linux\mm.h定义的,定义如下:
/*
 * A callback you can register to apply pressure to ageable caches.
 *
 * 'sc' is passed shrink_control which includes a count 'nr_to_scan'
 * and a 'gfpmask'.  It should look through the least-recently-used
 * 'nr_to_scan' entries and attempt to free them up.  It should return
 * the number of objects which remain in the cache.  If it returns -1, it means
 * it cannot do any scanning at this time (eg. there is a risk of deadlock).
 *
 * The 'gfpmask' refers to the allocation we are currently trying to
 * fulfil.
 *
 * Note that 'shrink' will be passed nr_to_scan == 0 when the VM is
 * querying the cache size, so a fastpath for that case is appropriate.
 */
struct   shrinker  {
int (*shrink)(struct shrinker *, struct shrink_control *sc);
int seeks; /* seeks to recreate an obj */

/* These are for internal use */
struct list_head list;
long nr; /* objs pending delete */
};
#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */
extern void  register_shrinker (struct shrinker *);
extern void  unregister_shrinker (struct shrinker *);
register_shrinker() unregister_shrinker() 则是在 common\mm\Vmscan.c 中定义的
/*
 * Add a shrinker callback to be called from the vm
 */
void  register_shrinker (struct shrinker *shrinker)
{
shrinker->nr = 0;
down_write(&shrinker_rwsem);
list_add_tail(&shrinker->list, &shrinker_list);
up_write(&shrinker_rwsem);
}
EXPORT_SYMBOL(register_shrinker);

/*
 * Remove one
 */
void  unregister_shrinker (struct shrinker *shrinker)
{
down_write(&shrinker_rwsem);
list_del(&shrinker->list);
up_write(&shrinker_rwsem);
}
EXPORT_SYMBOL(unregister_shrinker);

static inline int   do_shrinker_shrink (struct shrinker *shrinker,
     struct shrink_control *sc,
     unsigned long nr_to_scan)
{
sc->nr_to_scan = nr_to_scan;
return (*shrinker->shrink)(shrinker, sc);
}
所以只要注册一个Shrinker结构体,在内存分页回收时,系统将调用Shrinker结构体的函数指针
int (*shrink)(struct shrinker *, struct shrink_control *sc);,
下面我们来看看其实现Low memory killer的实现。 
lowmemorykiller.c 中,首先定义一个以 lowmem_shrink 为回调函数的指针的shrinker结构体lowmem_shrinker
static struct shrinker lowmem_shrinker = {
.shrink =  lowmem_shrink ,
.seeks = DEFAULT_SEEKS * 16
};
然后对 lowmem_shrink进行注册
static int __init  lowmem_init (void)
{
task_free_register(&task_nb);
register_shrinker(&lowmem_shrinker);
return 0;
}

static void __exit  lowmem_exit (void)
{
unregister_shrinker(&lowmem_shrinker);
task_free_unregister(&task_nb);
}

module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);
module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size,
 S_IRUGO | S_IWUSR);
module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
 S_IRUGO | S_IWUSR);
module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);

module_init(lowmem_init);
module_exit(lowmem_exit);
通过 module_init(lowmem_init) 注册, 在内存分页回收时,系统将调用 lowmem_shrink() 函数。
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, /* 6MB */
2 * 1024, /* 8MB */
4 * 1024, /* 16MB */
16 * 1024, /* 64MB */
};
static int  lowmem_minfree_size  = 4;
这就说明,当系统的空闲空间下降到 16 * 1024 个页面时, oom_adj 值为 12 或者更大的进程将被 Kill 掉;当系统的空闲空间下降到 4 * 1024 个页面时, oom_adj 值为 6 或者更大的进程将被Kill掉;依此类推。
其实更简明就是说: task_struct->signal_struct->oom_adj 越大的越优先被Kill,
oom_adj 的进程占用物理内存最多的那个进程会被优先Kill。
进程描述符中的 signal_struct->oom_adj 表示当内存短缺时进程被选择并Kill的优先级,值越大越可能被选中。当某个进程被选中后,内核会发送SIGKILL信号将其Kill掉。
实际上, Low Memory Killer 驱动程序会认为被用于缓存的存储空间都要被释放,但是,如果很大一部分缓存存储空间处于被锁定的状态,那么这将是一个非常严重的错误,并且当正常的oom killer被触发之前,进程是不会被Kill掉的。
lowmem_adj lowmem_minfree 上面的值只是个默认值 我们还可以通过以 写文件的方式 进行重写。我想该功能应该是通过 lowmemorykiller.c 中的如下代码开启该功能的
module_param_named (cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);
module_param_array_named ( adj lowmem_adj , int, &lowmem_adj_size,
 S_IRUGO | S_IWUSR);
module_param_array_named ( minfree lowmem_minfree , uint, &lowmem_minfree_size,
 S_IRUGO | S_IWUSR);
module_param_named ( debug_level lowmem_debug_level , uint, S_IRUGO | S_IWUSR);
在Android4.0以前,一直是通过system/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 //<category android:name="android.intent.category.HOME"/>
    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 /proc/sys/vm/overcommit_memory 1
    write /proc/sys/vm/min_free_order_shift 4
    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
在com.android.server.am.ActivityManagerService.java中,通过以下方式读取这些值。

可以在ActivityManagerService中清楚的看到: 

    static final int EMPTY_APP_ADJ;

    static final int HIDDEN_APP_MAX_ADJ;

    static final int HIDDEN_APP_MIN_ADJ;

    static final int HOME_APP_ADJ;

    static final int BACKUP_APP_ADJ;

    static final int SECONDARY_SERVER_ADJ;

    static final int HEAVY_WEIGHT_APP_ADJ;

    static final int PERCEPTIBLE_APP_ADJ;

    static final int VISIBLE_APP_ADJ;

    static final int FOREGROUND_APP_ADJ;

    static final int CORE_SERVER_ADJ = -12;

    static final int SYSTEM_ADJ = -16; 

   ActivityManagerService定义各种进程的oom_adj,CORE_SERVER_ADJ代表一些核心的服务的omm_adj,数值为-12,由前面的分析可知道,这类进程永远也不会被杀死。

其他未赋值的都在static块中进行了初始化,是通过system/rootdir/init.rc进行配置的:

Android <wbr>Low <wbr>memory <wbr>killer

在Android4.0中,则是通过 com.android.server.am.ProcessList 进行重写,重行配置的.
摘要如下:
    // These are the various interesting memory levels that we will give to
    // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
    // can't give it a different value for every possible kind of process.
    private final int[]  mOomAd j = new int[] {
            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
            BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, EMPTY_APP_ADJ
    };
    // These are the low-end OOM level limits.  This is appropriate for an
    // HVGA or smaller phone with less than 512MB.  Values are in KB.
    private final long[]  mOomMinFreeLow  = new long[] {
            8192, 12288, 16384,
            24576, 28672, 32768
    };
    // These are the high-end OOM level limits.  This is appropriate for a
    // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
    private final long[]  mOomMinFreeHigh  = new long[] {
            32768, 40960, 49152,
            57344, 65536, 81920
    };
...................................................................
   ProcessList () {
        MemInfoReader minfo = new MemInfoReader();
        minfo.readMemInfo();
        mTotalMemMb = minfo.getTotalSize()/(1024*1024);
        updateOomLevels(0, 0, false);
    }
..............................................................................
    private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {
        // Scale buckets from avail memory: at 300MB we use the lowest values to
        // 700MB or more for the top values.
        float scaleMem = ((float)(mTotalMemMb-300))/(700-300);

        // Scale buckets from screen size.
        int minSize = 320*480;  //  153600
        int maxSize = 1280*800; // 1024000  230400 870400  .264
        float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
        //Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth + " dh=" + displayHeight);

        StringBuilder adjString = new StringBuilder();
        StringBuilder memString = new StringBuilder();

        float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
        if (scale < 0) scale = 0;
        else if (scale > 1) scale = 1;
        for (int i=0; i<mOomAdj.length; i++) {
            long low = mOomMinFreeLow[i];
            long high = mOomMinFreeHigh[i];
            mOomMinFree[i] = (long)(low + ((high-low)*scale));

            if (i > 0) {
                adjString.append(',');
                memString.append(',');
            }
            adjString.append(mOomAdj[i]);
            memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);
        }

        //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString);
        if (write) {
            writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());
            writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());
        }
        // GB: 2048,3072,4096,6144,7168,8192
        // HC: 8192,10240,12288,14336,16384,20480
    }
更多内容请阅读《 Android Low memory killer(下)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值