欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新

Android Low Memory Killer

来源: 开发者 投稿于  被查看 13972 次 评论:84

Android Low Memory Killer


Low Memory Killer的原理

  在Android中,即使当用户退出应用程序之后,应用程序的进程也还是存在于系统中,这样是为了方便程序的再次启动,但是这样的话,随着打开的程序数量的增加,系统的内存会变得不足,就需要杀掉一部分进程以释放内存空间。至于是否需要杀死一些进程和哪些进程需要被杀死,是通过Low Memory Killer机制来进行判定的。

  Android的Low Memory Killer基于Linux的OOM机制,在Linux中,内存是以页面为单位分配的,当申请页面分配时如果内存不足会通过以下流程选择bad进程来杀掉从而释放内存:

alloc_pages -> out_of_memory() -> select_bad_process() -> badness()

  在Low Memory Killer中通过进程的oom_adj与占用内存的大小决定要杀死的进程,oom_adj越小越不容易被杀死。

  Low Memory Killer Driver在用户空间指定了一组内存临界值及与之一一对应的一组oom_adj值,当系统剩余内存位于内存临界值中的一个范围内时,如果一个进程的oom_adj值大于或等于这个临界值对应的oom_adj值就会被杀掉。

  可以通过修改/sys/module/lowmemorykiller/parameters/minfree与/sys/module/lowmemorykiller/parameters/adj来改变内存临界值及与之对应的oom_adj值。minfree中数值的单位是内存中的页面数量,一般情况下一个页面是4KB。
  比如如果向/sys/module/lowmemorykiller/parameters/adj写入0,8,向/sys/module/lowmemorykiller/parameters/minfree中写入1024,4096,假设一个页面大小为4KB,这样当系统空闲内存位于1024*4~4096*4KB之间时oom_adj大于等于8的进程就会被杀掉。

  在lowmemorykiller.c中定义了阈值表的默认值,可以通过init.rc自定义:

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; 

  在init.rc中定义了init进程的oom_adj为-16,不可能会被杀死(init的PID是1):

on early-
    write /proc//oom_adj -

  在Linux中有一个kswapd的内核线程,当linux回收内存分页的时候,kswapd线程将会遍历一张shrinker链表,并执行回调,定义如下:


/*
 * A callback you can register to apply pressure to ageable caches.
 *
 * 'shrink' is passed 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.
*/
 (*shrink)( seeks;      

    
     nr;         DEFAULT_SEEKS 2 /* A good number if you don't know better. */
  register_shrinker( shrinker *  unregister_shrinker( shrinker *);

  通过register_shrinker与unregister_shrinker向shrinker链表中添加或移除回调。当注册Shrinker后就可以在回收内存分页时按自己定义的规则释放内存。

  Android Low Memory Killer的代码在drivers/staging/android/lowmemorykiller.c中,通过以下代码在模块初始化时注册Shrinker:

  lowmem_shrink(  shrinker lowmem_shrinker === DEFAULT_SEEKS *   __init lowmem_init(&   __exit lowmem_exit(&

  这样就可以在回收内存分页时调用lowmem_shrink函数。

Low Memory Killer的实现

  lowmem_shrink的定义如下:

lowmem_shrink( task_struct * task_struct *selected = rem = min_adj = OOM_ADJUST_MAX + selected_tasksize = array_size = other_free = other_file = (lowmem_adj_size <= (lowmem_minfree_size <= (i = ; i < array_size; i++ (other_free < lowmem_minfree[i] &&<= (nr_to_scan > , = global_page_state(NR_ACTIVE_ANON) +++ (nr_to_scan <= || min_adj == OOM_ADJUST_MAX + , =& mm_struct *= p-> (!= mm-> (oom_adj <= (tasksize <= (oom_adj < (oom_adj == selected_oom_adj &&<====, ->pid, p->, ->pid, selected->-=, & View Code

  分开来看这段代码,首先取得内存阈值表的大小,取阈值表数组大小与lowmem_adj_size,lowmem_minfree_size的较小值,然后通过globa_page_state获得当前剩余内存的大小,然后跟内存阈值表中的阈值相比较获得min_adj与selected_oom_adj:

 array_size = other_free = other_file = (lowmem_adj_size <= (lowmem_minfree_size <= (i = ; i < array_size; i++ (other_free < lowmem_minfree[i] && other_file <=selected_oom_adj = min_adj;

read_lock(& mm_struct *= p-> (!= mm->
     (oom_adj <
    tasksize = (tasksize <= 
     (oom_adj < (oom_adj == selected_oom_adj &&<=
    selected ===, ->pid, p->

  如果选择出了符合条件的进程,发送SIGNAL信号Kill掉:

, ->pid, selected->-=

oom_adj与上层Process Importance的关系

  我们知道,在上层进程按重要性可以分为:Foreground process,Visible process,Service process,Background process与Empty process,那么这些重要性怎么与Low Memory Killer中的oom_adj对应起来的呢?

  在ActivityManager.RunningAppProcessInfo中我们可以看到如下关于importance的定义:


    IMPORTANCE_PERSISTENT = 50
    IMPORTANCE_FOREGROUND = 100
    IMPORTANCE_VISIBLE = 200
    IMPORTANCE_PERCEPTIBLE = 130
    IMPORTANCE_CANT_SAVE_STATE = 170
    IMPORTANCE_SERVICE = 300
    IMPORTANCE_BACKGROUND = 400
    IMPORTANCE_EMPTY = 500;

  这些常量表示了Process的Importance等级,而在ProcessList中我们会发现关于adj的一些定义:


   HIDDEN_APP_MAX_ADJ = 15  HIDDEN_APP_MIN_ADJ = 9
   SERVICE_B_ADJ = 8
   PREVIOUS_APP_ADJ = 7
   HOME_APP_ADJ = 6
   SERVICE_ADJ = 5
   BACKUP_APP_ADJ = 4
   HEAVY_WEIGHT_APP_ADJ = 3
   PERCEPTIBLE_APP_ADJ = 2
   VISIBLE_APP_ADJ = 1
   FOREGROUND_APP_ADJ = 0
   PERSISTENT_PROC_ADJ = -12
   SYSTEM_ADJ = -16;

  我们可以看到:

   PREVIOUS_APP_ADJ = 7   HOME_APP_ADJ = 6;

  并不是所有的Background process的等级都是相同的。

  关于ADJ与Importance的值都找到了,那么它们是怎么对应起来的呢?Activity实际是由ActivityManagerService来管理的,在ActivityManagerService中我们可以找到以下函数:

  oomAdjToImportance( (adj >= (currApp != = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1  (adj >=  (adj >= (currApp != = 0  (adj >=  (adj >=  (adj >=  (adj >=

  在这个函数中实现了根据adj设置importance的功能。

  我们还可以看到SERVICE还分为SERVICE_B_ADJ与SERVICE_ADJ,等级是不一样的,并不是所有Service的优先级都比Background process的优先级高。当调用Service的startForeground后,Service的importance就变为了IMPORTANCE_PERCEPTIBLE(在记忆中曾经将Service设置为foreground并打印出其importance的值与IMPORTANCE_PERCEPTIBLE相等),对应的adj是PERCEPTIBLE_APP_ADJ,即2,已经很难被系统杀死了。


   PERSISTENT_PROC_ADJ = -12
   SYSTEM_ADJ = -16;

  像电话等进程的adj为-12已基本不可能被杀死了,而在前面已经看到了,init.rc中将init进程的oom_adj设置为了-16,已经是永生进程了。

 

相关链接:

lowermemorykiller.txt

lowermemorykiller.c

shrinker_list

用户评论