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-init
- # Set init and its forked children's oom_adj.
- write /proc/1/oom_adj -16
在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.
- */
- struct shrinker {
- int (*shrink)(int nr_to_scan, gfp_t gfp_mask);
- 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向shrinker链表中添加或移除回调。当注册Shrinker后就可以在回收内存分页时按自己定义的规则释放内存。
Android Low Memory Killer的代码在drivers/staging/android/lowmemorykiller.c中,通过以下代码在模块初始化时注册Shrinker:
- static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask);
-
- static struct shrinker lowmem_shrinker = {
- .shrink = lowmem_shrink,
- .seeks = DEFAULT_SEEKS * 16
- };
-
- static int __init lowmem_init(void)
- {
- register_shrinker(&lowmem_shrinker);
- return 0;
- }
-
- static void __exit lowmem_exit(void)
- {
- unregister_shrinker(&lowmem_shrinker);
- }
-
- module_init(lowmem_init);
- module_exit(lowmem_exit);
这样就可以在回收内存分页时调用lowmem_shrink函数。
Low Memory Killer的实现
lowmem_shrink的定义如下:
- static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
- {
- struct task_struct *p;
- struct task_struct *selected = NULL;
- int rem = 0;
- int tasksize;
- int i;
- int min_adj = OOM_ADJUST_MAX + 1;
- int selected_tasksize = 0;
- int selected_oom_adj;
- int array_size = ARRAY_SIZE(lowmem_adj);
- int other_free = global_page_state(NR_FREE_PAGES);
- int other_file = global_page_state(NR_FILE_PAGES);
-
- if (lowmem_adj_size < array_size)
- array_size = lowmem_adj_size;
- if (lowmem_minfree_size < array_size)
- array_size = lowmem_minfree_size;
- for (i = 0; i < array_size; i++) {
- if (other_free < lowmem_minfree[i] &&
- other_file < lowmem_minfree[i]) {
- min_adj = lowmem_adj[i];
- break;
- }
- }
- if (nr_to_scan > 0)
- lowmem_print(3, "lowmem_shrink %d, %x, ofree %d %d, ma %d\n",
- nr_to_scan, gfp_mask, other_free, other_file,
- min_adj);
- rem = global_page_state(NR_ACTIVE_ANON) +
- global_page_state(NR_ACTIVE_FILE) +
- global_page_state(NR_INACTIVE_ANON) +
- global_page_state(NR_INACTIVE_FILE);
- 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;
- }
- selected_oom_adj = min_adj;
-
- read_lock(&tasklist_lock);
- for_each_process(p) {
- struct mm_struct *mm;
- int oom_adj;
-
- task_lock(p);
- mm = p->mm;
- if (!mm) {
- task_unlock(p);
- continue;
- }
- oom_adj = mm->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);
- }
- if (selected) {
- 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;
- }
- lowmem_print(4, "lowmem_shrink %d, %x, return %d\n",
- nr_to_scan, gfp_mask, rem);
- read_unlock(&tasklist_lock);
- return rem;
- }
分开来看这段代码,首先取得内存阈值表的大小,取阈值表数组大小与lowmem_adj_size,lowmem_minfree_size的较小值,然后通过globa_page_state获得当前剩余内存的大小,然后跟内存阈值表中的阈值相比较获得min_adj与selected_oom_adj:
- int array_size = ARRAY_SIZE(lowmem_adj);
- int other_free = global_page_state(NR_FREE_PAGES);
- int other_file = global_page_state(NR_FILE_PAGES);
-
- if (lowmem_adj_size < array_size)
- array_size = lowmem_adj_size;
- if (lowmem_minfree_size < array_size)
- array_size = lowmem_minfree_size;
- for (i = 0; i < array_size; i++) {
- if (other_free < lowmem_minfree[i] && other_file < lowmem_minfree[i]) {
- min_adj = lowmem_adj[i];
- break;
- }
- }selected_oom_adj = min_adj;
遍历所有进程找到oom_adj>min_adj并且占用内存大的进程:
- read_lock(&tasklist_lock);
- for_each_process(p) {
- struct mm_struct *mm;
- int oom_adj;
-
- task_lock(p);
- mm = p->mm;
- if (!mm) {
- task_unlock(p);
- continue;
- }
- oom_adj = mm->oom_adj;
- //获取task_struct->struct_mm->oom_adj,如果小于警戒值min_adj不做处理
- if (oom_adj < min_adj) {
- task_unlock(p);
- continue;
- }
- //如果走到这里说明oom_adj>=min_adj,即超过警戒值
- //获取内存占用大小,若<=0,不做处理
- tasksize = get_mm_rss(mm);
- task_unlock(p);
- if (tasksize <= 0)
- continue;
- //如果之前已经先择了一个进程,比较当前进程与之前选择的进程的oom_adj与内存占
- //用大小,如果oom_adj比之前选择的小或相等而内存占用比之前选择的进程小,不做处理。
- if (selected) {
- if (oom_adj < selected_oom_adj)
- continue;
- if (oom_adj == selected_oom_adj &&
- tasksize <= selected_tasksize)
- continue;
- }
- //走到这里表示当前进程比之前选择的进程oom_adj大或相等但占用内存大,选择当前进程
- 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);
- }
如果选择出了符合条件的进程,发送SIGNAL信号Kill掉:
- if (selected) {
- 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;
- }
oom_adj与上层Process Importance的关系
我们知道,在上层进程按重要性可以分为:Foreground process,Visible process,Service process,Background process与Empty process,那么这些重要性怎么与Low Memory Killer中的oom_adj对应起来的呢?
在ActivityManager.RunningAppProcessInfo中我们可以看到如下关于importance的定义:
- /**
- * Constant for {@link #importance}: this is a persistent process.
- * Only used when reporting to process observers.
- * @hide
- */
- public static final int IMPORTANCE_PERSISTENT = 50;
-
- /**
- * Constant for {@link #importance}: this process is running the
- * foreground UI.
- */
- public static final int IMPORTANCE_FOREGROUND = 100;
-
- /**
- * Constant for {@link #importance}: this process is running something
- * that is actively visible to the user, though not in the immediate
- * foreground.
- */
- public static final int IMPORTANCE_VISIBLE = 200;
-
- /**
- * Constant for {@link #importance}: this process is running something
- * that is considered to be actively perceptible to the user. An
- * example would be an application performing background music playback.
- */
- public static final int IMPORTANCE_PERCEPTIBLE = 130;
-
- /**
- * Constant for {@link #importance}: this process is running an
- * application that can not save its state, and thus can't be killed
- * while in the background.
- * @hide
- */
- public static final int IMPORTANCE_CANT_SAVE_STATE = 170;
-
- /**
- * Constant for {@link #importance}: this process is contains services
- * that should remain running.
- */
- public static final int IMPORTANCE_SERVICE = 300;
-
- /**
- * Constant for {@link #importance}: this process process contains
- * background code that is expendable.
- */
- public static final int IMPORTANCE_BACKGROUND = 400;
-
- /**
- * Constant for {@link #importance}: this process is empty of any
- * actively running code.
- */
- public static final int IMPORTANCE_EMPTY = 500;
这些常量表示了Process的Importance等级,而在ProcessList中我们会发现关于adj的一些定义:
- // This is a process only hosting activities that are not visible,
- // so it can be killed without any disruption.
- static final int HIDDEN_APP_MAX_ADJ = 15;
- static int HIDDEN_APP_MIN_ADJ = 9;
-
- // The B list of SERVICE_ADJ -- these are the old and decrepit
- // services that aren't as shiny and interesting as the ones in the A list.
- static final int SERVICE_B_ADJ = 8;
-
- // This is the process of the previous application that the user was in.
- // This process is kept above other things, because it is very common to
- // switch back to the previous app. This is important both for recent
- // task switch (toggling between the two top recent apps) as well as normal
- // UI flow such as clicking on a URI in the e-mail app to view in the browser,
- // and then pressing back to return to e-mail.
- static final int PREVIOUS_APP_ADJ = 7;
-
- // This is a process holding the home application -- we want to try
- // avoiding killing it, even if it would normally be in the background,
-
- // because the user interacts with it so much.
- static final int HOME_APP_ADJ = 6;
-
- // This is a process holding an application service -- killing it will not
- // have much of an impact as far as the user is concerned.
- static final int SERVICE_ADJ = 5;
-
- // This is a process currently hosting a backup operation. Killing it
- // is not entirely fatal but is generally a bad idea.
- static final int BACKUP_APP_ADJ = 4;
-
- // This is a process with a heavy-weight application. It is in the
- // background, but we want to try to avoid killing it. Value set in
- // system/rootdir/init.rc on startup.
- static final int HEAVY_WEIGHT_APP_ADJ = 3;
-
- // This is a process only hosting components that are perceptible to the
- // user, and we really want to avoid killing them, but they are not
- // immediately visible. An example is background music playback.
- static final int PERCEPTIBLE_APP_ADJ = 2;
-
- // This is a process only hosting activities that are visible to the
- // user, so we'd prefer they don't disappear.
- static final int VISIBLE_APP_ADJ = 1;
-
- // This is the process running the current foreground app. We'd really
- // rather not kill it!
- static final int FOREGROUND_APP_ADJ = 0;
-
- // This is a system persistent process, such as telephony. Definitely
- // don't want to kill it, but doing so is not completely fatal.
- static final int PERSISTENT_PROC_ADJ = -12;
-
- // The system process runs at the default adjustment.
- static final int SYSTEM_ADJ = -16;
我们可以看到:
- static final int PREVIOUS_APP_ADJ = 7;
- static final int HOME_APP_ADJ = 6;
并不是所有的Background process的等级都是相同的。
关于ADJ与Importance的值都找到了,那么它们是怎么对应起来的呢?Activity实际是由ActivityManagerService来管理的,在ActivityManagerService中我们可以找到以下函数:
- static int oomAdjToImportance(int adj, ActivityManager.RunningAppProcessInfo currApp) {
- if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
- if (currApp != null) {
- currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
- }
- return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
- } else if (adj >= ProcessList.SERVICE_B_ADJ) {
- return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
- } else if (adj >= ProcessList.HOME_APP_ADJ) {
- if (currApp != null) {
- currApp.lru = 0;
- }
- return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
- } else if (adj >= ProcessList.SERVICE_ADJ) {
- return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
- } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
- return ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
- } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
- return ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
- } else if (adj >= ProcessList.VISIBLE_APP_ADJ) {
- return ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
- } else {
- return ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
- }
- }
在这个函数中实现了根据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,已经很难被系统杀死了。
- // This is a system persistent process, such as telephony. Definitely
- // don't want to kill it, but doing so is not completely fatal.
- static final int PERSISTENT_PROC_ADJ = -12;
-
- // The system process runs at the default adjustment.
- static final int SYSTEM_ADJ = -16;
像电话等进程的adj为-12已基本不可能被杀死了,而在前面已经看到了,init.rc中将init进程的oom_adj设置为了-16,已经是永生进程了。
相关链接:
lowermemorykiller.txt
lowermemorykiller.c
shrinker_list
(angeldevil) |