Android中,进程的生命周期都是由系统控制的。即使用户在界面上关掉一个应用,切换到了别的应用,那个应用的进程依然是存在于内存之中的。这样设计的目的是为了下次启动应用能更加快速。当然,随着系统运行时间的增长,内存中的进程可能会越来越多,而可用的内存则将会越来越少。Android Kernel会定时执行一次检查,杀死一些进程,释放掉内存。
那么,如何来判断,哪些进程是需要杀死的呢?答案就是:low memory killer机制。
Android的low memory killer是基于linux的OOM(out of memory)规则改进而来的。OOM通过一些比较复杂的评分机制,对进程进行打分,然后将分数高的进程判定为bad进程,杀死进程并释放内存。OOM只有当系统内存不足的时候才会启动检查,而low memory killer则不仅是在应用程序分配内存发现内存不足时启动检查,它也会定时地进行检查。
Low memory killer主要是通过进程的oom_adj来判定进程的重要程度的。oom_adj的大小和进程的类型以及进程被调度的次序有关。
Low memory killer的具体实现在kernel,比如对于android 4.4.3所用的kernel_3.4,代码在:linux/kernel/drivers/staging/android/lowmemorykiller.c。
其原理很简单,在linux中,存在一个名为kswapd的内核线程,当linux回收存放分页的时候,kswapd线程将会遍历一张shrinker链表,并执行回调,或者某个app分配内存,发现可用内存不足时,则内核会阻塞请求分配内存的进程分配内存的过程,并在该进程中去执行lowmemorykiller来释放内存****。
struct shrinker的定义在linux/kernel/include/linux/shrinker.h,具体如下:
1struct shrinker { 2 int (*shrink)(struct shrinker *, struct shrink_control *sc); 3 int seeks;/* seeks to recreate an obj */ 4 long batch;/* reclaim batch size, 0 = default */ 5 6 /* These are for internal use */ 7 struct list_head list; 8 atomic_long_t nr_in_batch; /* objs pending delete */ 9}; 10#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */ 11extern void register_shrinker(struct shrinker *); 12extern void unregister_shrinker(struct shrinker *); 13#endif
**所以,只要注册 shrinker,就可以在内存分页回收时根据规则释放内存****,**下面我们来看看lowmemorykiller的具体实现。首先是定义shrinker结构体,lowmem_shrink为回调函数的指针,**当有内存分页回收的时候,获其他有需要的时机,**这个函数将会被调用。
1static struct shrinker lowmem_shrinker = { 2 .shrink = lowmem_shrink, 3 .seeks = DEFAULT_SEEKS * 16 4};
初始化模块时进行注册,模块退出时注销。
1static int __init lowmem_init(void) 2{ 3 register_shrinker(&lowmem_shrinker); 4 return 0; 5} 6static void __exit lowmem_exit(void) 7{ 8 unregister_shrinker(&lowmem_shrinker); 9}
Android中,存在着一张内存阈值表,这张阈值表是可以在init.rc中进行配置的,合理配置这张表,对于小内存设备有非常重要的作用。我们来看lowmemorykiller.c中这张默认的阈值表:
1static int lowmem_adj[6] = { 2 0, 3 1, 4 6, 5 12, 6}; 7static int lowmem_adj_size = 4; 8static int lowmem_minfree[6] = { 9 3 * 512,/* 6MB */ 10 2 * 1024,/* 8MB */ 11 4 * 1024,/* 16MB */ 12 16 * 1024,/* 64MB */ 13}; 14static int lowmem_minfree_size = 4;
lowmem_adj中各项数值代表阈值的警戒级数,lowmem_minfree代表对应级数的剩余内存。也就是说,当系统的可用内存小于6MB时,警戒级数为0;当系统可用内存小于8M而大于6M时,警戒级数为1;当可用内存小于64M大于16MB时,警戒级数为12。Low memory killer的规则就是根据当前系统的可用内存多少来获取当前的警戒级数,如果进程的oom_adj大于警戒级数并且最大,进程将会被杀死(具有相同omm_adj的进程,则杀死占用内存较多的)。omm_adj越小,代表进程越重要。一些前台的进程,oom_adj会比较小,而后台的服务,omm_adj会比较大,所以当内存不足的时候,Low memory killer必然先杀掉的是后台服务而不是前台的进程。
OK,现在我们来看具体代码,也就是lowmem_shrink这个回调函数,先来:
1static int lowmem_minfree_size = 4; 2 3static unsigned long lowmem_deathpending_timeout; 4 5#define lowmem_print(level, x...)\ 6 do {\ 7 if (lowmem_debug_level >= (level))\ 8 printk(x);\ 9 } while (0) 10 11static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) 12{ 13 struct task_struct *tsk; 14 struct task_struct *selected = NULL; 15 int rem = 0; 16 int tasksize; 17 int i; 18 int min_score_adj = OOM_SCORE_ADJ_MAX + 1; 19 int selected_tasksize = 0; 20 int selected_oom_score_adj; 21 int array_size = ARRAY_SIZE(lowmem_adj); 22 int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages; 23 int other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM); 24 25 if (lowmem_adj_size < array_size) 26 array_size = lowmem_adj_size; 27 if (lowmem_minfree_size < array_size) 28 array_size = lowmem_minfree_size; 29 for (i = 0; i < array_size; i++) { 30 if (other_free < lowmem_minfree[i] && 31 other_file < lowmem_minfree[i]) { 32 min_score_adj = lowmem_adj[i]; 33 break; 34 } 35 } 36 if (sc->nr_to_scan > 0) 37 lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %d\n", 38 sc->nr_to_scan, sc->gfp_mask, other_free, 39 other_file, min_score_adj); 40 rem = global_page_state(NR_ACTIVE_ANON) + 41 global_page_state(NR_ACTIVE_FILE) + 42 global_page_state(NR_INACTIVE_ANON) + 43 global_page_state(NR_INACTIVE_FILE); 44 if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) { 45 lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n", 46 sc->nr_to_scan, sc->gfp_mask, rem); 47 return rem; 48 } 49 selected_oom_score_adj = min_score_adj; 50 51 rcu_read_lock(); 52 for_each_process(tsk) { 53 struct task_struct *p; 54 int oom_score_adj; 55 56 if (tsk->flags & PF_KTHREAD) 57 continue; 58 59 p = find_lock_task_mm(tsk); 60 if (!p) 61 continue; 62 63 if (test_tsk_thread_flag(p, TIF_MEMDIE) && 64 time_before_eq(jiffies, lowmem_deathpending_timeout)) { 65 task_unlock(p); 66 rcu_read_unlock(); 67 return 0; 68 } 69 oom_score_adj = p->signal->oom_score_adj; 70 if (oom_score_adj < min_score_adj) { 71 task_unlock(p); 72 continue; 73 } 74 tasksize = get_mm_rss(p->mm); 75 task_unlock(p); 76 if (tasksize <= 0) 77 continue; 78 if (selected) { 79 if (oom_score_adj < selected_oom_score_adj) 80 continue; 81 if (oom_score_adj == selected_oom_score_adj && 82 tasksize <= selected_tasksize) 83 continue; 84 } 85 selected = p; 86 selected_tasksize = tasksize; 87 selected_oom_score_adj = oom_score_adj; 88 lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", 89 p->pid, p->comm, oom_score_adj, tasksize); 90 } 91 if (selected) { 92 lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", 93 selected->pid, selected->comm, 94 selected_oom_score_adj, selected_tasksize); 95 lowmem_deathpending_timeout = jiffies + HZ; 96 send_sig(SIGKILL, selected, 0); 97 set_tsk_thread_flag(selected, TIF_MEMDIE); 98 rem -= selected_tasksize; 99 } 100 lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n", 101 sc->nr_to_scan, sc->gfp_mask, rem); 102 rcu_read_unlock(); 103 return rem; 104}
第22行至第35行。通过global_page_state()函数获取系统当前可用的内存大小,然后根据可用内存大小及内存阈值表,来计算系统当前的警戒等级。
第40行,计算rem值。
第44行至第48行这个if-block,发现此时系统的内存状况还是很不错的,于是就什麽也不做,直接返回了。
第49行至第90行,遍历系统中所有的进程,选中将要杀掉的那个进程。第56行,跳过内核线程,内核线程不参加这个杀进程的游戏。第69行至第73行,进程的oom_score_adj小于警戒阈值,则无视。第74行,获取进程所占用的内存大小,RSS值。第78行至第84行,如果这个进程的oom_score_adj小于我们已经选中的那个进程的oom_score_adj,或者这个进程的oom_score_adj等于我们已经选中的那个进程的oom_score_adj,但其所占用的内存大小tasksize小于我们已经选中的那个进程所占用内存大小,则继续寻找下一个进程。第85至第89行,选中正在遍历的这个的进程,更新selected_tasksize为这个进程所占用的内存大小tasksize,更新selected_oom_score_adj为这个进程的oom_score_adj。
第91行至第99行,杀死选中的进程。先是更新lowmem_deathpending_timeout,然后便是给进程发送一个signal SIGKILL,接下来是设置进程的标记为TIF_MEMDIE,最后则是更新一下rem的值。
adj值的设置
在lowmemorykiller的code中我们有看到一个默认的阈值表。如我们前面所提到的那样,各种各样的设备、产品也可以自己定制这个值。这种定制主要是通过导出一些内核变量来实现的,具体代码如下:
1#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES 2static int lowmem_oom_adj_to_oom_score_adj(int oom_adj) 3{ 4 if (oom_adj == OOM_ADJUST_MAX) 5 return OOM_SCORE_ADJ_MAX; 6 else 7 return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; 8} 9 10static void lowmem_autodetect_oom_adj_values(void) 11{ 12 int i; 13 int oom_adj; 14 int oom_score_adj; 15 int array_size = ARRAY_SIZE(lowmem_adj); 16 17 if (lowmem_adj_size < array_size) 18 array_size = lowmem_adj_size; 19 20 if (array_size <= 0) 21 return; 22 23 oom_adj = lowmem_adj[array_size - 1]; 24 if (oom_adj > OOM_ADJUST_MAX) 25 return; 26 27 oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj); 28 if (oom_score_adj <= OOM_ADJUST_MAX) 29 return; 30 31 lowmem_print(1, "lowmem_shrink: convert oom_adj to oom_score_adj:\n"); 32 for (i = 0; i < array_size; i++) { 33 oom_adj = lowmem_adj[i]; 34 oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj); 35 lowmem_adj[i] = oom_score_adj; 36 lowmem_print(1, "oom_adj %d => oom_score_adj %d\n", 37 oom_adj, oom_score_adj); 38 } 39} 40 41static int lowmem_adj_array_set(const char *val, const struct kernel_param *kp) 42{ 43 int ret; 44 45 ret = param_array_ops.set(val, kp); 46 47 /* HACK: Autodetect oom_adj values in lowmem_adj array */ 48 lowmem_autodetect_oom_adj_values(); 49 50 return ret; 51} 52 53static int lowmem_adj_array_get(char *buffer, const struct kernel_param *kp) 54{ 55 return param_array_ops.get(buffer, kp); 56} 57 58static void lowmem_adj_array_free(void *arg) 59{ 60 param_array_ops.free(arg); 61} 62 63static struct kernel_param_ops lowmem_adj_array_ops = { 64 .set = lowmem_adj_array_set, 65 .get = lowmem_adj_array_get, 66 .free = lowmem_adj_array_free, 67}; 68 69static const struct kparam_array __param_arr_adj = { 70 .max = ARRAY_SIZE(lowmem_adj), 71 .num = &lowmem_adj_size, 72 .ops = ¶m_ops_int, 73 .elemsize = sizeof(lowmem_adj[0]), 74 .elem = lowmem_adj, 75}; 76#endif 77 78module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); 79#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES 80__module_param_call(MODULE_PARAM_PREFIX, adj, 81 &lowmem_adj_array_ops, 82 .arr = &__param_arr_adj, 83 S_IRUGO | S_IWUSR, -1); 84__MODULE_PARM_TYPE(adj, "array of int"); 85#else 86module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, 87 S_IRUGO | S_IWUSR); 88#endif 89module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, 90 S_IRUGO | S_IWUSR); 91module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
lowmemorykiller在此处总共导出了4个内核变量,其中两个是内核数组。我们可以在如下位置访问到这些内核变量:/sys/module/lowmemorykiller/parameters。在init.rc文件中会设置这些内核变量的属性(system/core/rootdir/init.rc),以便于后面系统对这些值进行修改:
1281 chown root system /sys/module/lowmemorykiller/parameters/adj 2282 chmod 0664 /sys/module/lowmemorykiller/parameters/adj 3283 chown root system /sys/module/lowmemorykiller/parameters/minfree 4284 chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
那通常情况下,比如在Nexus 7或类似的设备上,adj值又是在什麽时候设置的呢?设置的那些值依据是什麽呢,是一个经验值呢还是有什麽算法来算出那些值?
搜索android4.4.3_r1.1的整个codebase,我们发现lowmemorykiller所导出的那些值只在ProcessList.updateOomLevels()方法中被修改了。接着我们就来具体看一下这个方法的实现(实现此方法的文件位置为frameworks/base/services/java/com/android/server/am/ProcessList.java):
1 // OOM adjustments for processes in various states: 2 3 // Adjustment used in certain places where we don't know it yet. 4 // (Generally this is something that is going to be cached, but we 5 // don't know the exact value in the cached range to assign yet.) 6 static final int UNKNOWN_ADJ = 16; 7 8 // This is a process only hosting activities that are not visible, 9 // so it can be killed without any disruption. 10 static final int CACHED_APP_MAX_ADJ = 15; 11 static final int CACHED_APP_MIN_ADJ = 9; 12 13 // The B list of SERVICE_ADJ -- these are the old and decrepit 14 // services that aren't as shiny and interesting as the ones in the A list. 15 static final int SERVICE_B_ADJ = 8; 16 17 // This is the process of the previous application that the user was in. 18 // This process is kept above other things, because it is very common to 19 // switch back to the previous app. This is important both for recent 20 // task switch (toggling between the two top recent apps) as well as normal 21 // UI flow such as clicking on a URI in the e-mail app to view in the browser, 22 // and then pressing back to return to e-mail. 23 static final int PREVIOUS_APP_ADJ = 7; 24 25 // This is a process holding the home application -- we want to try 26 // avoiding killing it, even if it would normally be in the background, 27 // because the user interacts with it so much. 28 static final int HOME_APP_ADJ = 6; 29 30 // This is a process holding an application service -- killing it will not 31 // have much of an impact as far as the user is concerned. 32 static final int SERVICE_ADJ = 5; 33 34 // This is a process with a heavy-weight application. It is in the 35 // background, but we want to try to avoid killing it. Value set in 36 // system/rootdir/init.rc on startup. 37 static final int HEAVY_WEIGHT_APP_ADJ = 4; 38 39 // This is a process currently hosting a backup operation. Killing it 40 // is not entirely fatal but is generally a bad idea. 41 static final int BACKUP_APP_ADJ = 3; 42 43 // This is a process only hosting components that are perceptible to the 44 // user, and we really want to avoid killing them, but they are not 45 // immediately visible. An example is background music playback. 46 static final int PERCEPTIBLE_APP_ADJ = 2; 47 48 // This is a process only hosting activities that are visible to the 49 // user, so we'd prefer they don't disappear. 50 static final int VISIBLE_APP_ADJ = 1; 51 52 // This is the process running the current foreground app. We'd really 53 // rather not kill it! 54 static final int FOREGROUND_APP_ADJ = 0; 55 56 // This is a system persistent process, such as telephony. Definitely 57 // don't want to kill it, but doing so is not completely fatal. 58 static final int PERSISTENT_PROC_ADJ = -12; 59 60 // The system process runs at the default adjustment. 61 static final int SYSTEM_ADJ = -16; 62 63 // Special code for native processes that are not being managed by the system (so 64 // don't have an oom adj assigned by the system). 65 static final int NATIVE_ADJ = -17; 66 67 // Memory pages are 4K. 68 static final int PAGE_SIZE = 4*1024; 69 70 // These are the various interesting memory levels that we will give to 71 // the OOM killer. Note that the OOM killer only supports 6 slots, so we 72 // can't give it a different value for every possible kind of process. 73 private final int[] mOomAdj = new int[] { 74 FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ, 75 BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ 76 }; 77 // These are the low-end OOM level limits. This is appropriate for an 78 // HVGA or smaller phone with less than 512MB. Values are in KB. 79 private final long[] mOomMinFreeLow = new long[] { 80 8192, 12288, 16384, 81 24576, 28672, 32768 82 }; 83 // These are the high-end OOM level limits. This is appropriate for a 84 // 1280x800 or larger screen with around 1GB RAM. Values are in KB. 85 private final long[] mOomMinFreeHigh = new long[] { 86 49152, 61440, 73728, 87 86016, 98304, 122880 88 }; 89 // The actual OOM killer memory levels we are using. 90 private final long[] mOomMinFree = new long[mOomAdj.length]; 91 92 private final long mTotalMemMb; 93 94 private void updateOomLevels(int displayWidth, int displayHeight, boolean write) { 95 // Scale buckets from avail memory: at 300MB we use the lowest values to 96 // 700MB or more for the top values. 97 float scaleMem = ((float)(mTotalMemMb-300))/(700-300); 98 99 // Scale buckets from screen size. 100 int minSize = 480*800; // 384000 101 int maxSize = 1280*800; // 1024000 230400 870400 .264 102 float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize); 103 if (false) { 104 Slog.i("XXXXXX", "scaleMem=" + scaleMem); 105 Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth 106 + " dh=" + displayHeight); 107 } 108 109 StringBuilder adjString = new StringBuilder(); 110 StringBuilder memString = new StringBuilder(); 111 112 float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp; 113 if (scale < 0) scale = 0; 114 else if (scale > 1) scale = 1; 115 int minfree_adj = Resources.getSystem().getInteger( 116 com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAdjust); 117 int minfree_abs = Resources.getSystem().getInteger( 118 com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAbsolute); 119 if (false) { 120 Slog.i("XXXXXX", "minfree_adj=" + minfree_adj + " minfree_abs=" + minfree_abs); 121 } 122 123 for (int i=0; i<mOomAdj.length; i++) { 124 long low = mOomMinFreeLow[i]; 125 long high = mOomMinFreeHigh[i]; 126 mOomMinFree[i] = (long)(low + ((high-low)*scale)); 127 } 128 129 if (minfree_abs >= 0) { 130 for (int i=0; i<mOomAdj.length; i++) { 131 mOomMinFree[i] = (long)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]); 132 } 133 } 134 135 if (minfree_adj != 0) { 136 for (int i=0; i<mOomAdj.length; i++) { 137 mOomMinFree[i] += (long)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]); 138 if (mOomMinFree[i] < 0) { 139 mOomMinFree[i] = 0; 140 } 141 } 142 } 143 144 // The maximum size we will restore a process from cached to background, when under 145 // memory duress, is 1/3 the size we have reserved for kernel caches and other overhead 146 // before killing background processes. 147 mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3; 148 149 for (int i=0; i<mOomAdj.length; i++) { 150 if (i > 0) { 151 adjString.append(','); 152 memString.append(','); 153 } 154 adjString.append(mOomAdj[i]); 155 memString.append((mOomMinFree[i]*1024)/PAGE_SIZE); 156 } 157 158 // Ask the kernel to try to keep enough memory free to allocate 3 full 159 // screen 32bpp buffers without entering direct reclaim. 160 int reserve = displayWidth * displayHeight * 4 * 3 / 1024; 161 int reserve_adj = Resources.getSystem().getInteger(com.android.internal.R.integer.config_extraFreeKbytesAdjust); 162 int reserve_abs = Resources.getSystem().getInteger(com.android.internal.R.integer.config_extraFreeKbytesAbsolute); 163 164 if (reserve_abs >= 0) { 165 reserve = reserve_abs; 166 } 167 168 if (reserve_adj != 0) { 169 reserve += reserve_adj; 170 if (reserve < 0) { 171 reserve = 0; 172 } 173 } 174 175 //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString); 176 if (write) { 177 writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString()); 178 writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString()); 179 SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve)); 180 } 181 // GB: 2048,3072,4096,6144,7168,8192 182 // HC: 8192,10240,12288,14336,16384,20480 183 }
adj值是一组写死的固定的值,具体可以参考mOomAdj的定义。
第123行至第127行,是第一轮计算各个adj所对应的minimum free memory阈值。计算各个值的算式为(long)(low + ((high-low)*scale))。low值和high值都是预定义的固定的经验值,比较关键的是那个scale值。在前面计算scale的部分,我们可以看到,它会先计算一个memory的scale值(为((float)(mTotalMemMb-300))/(700-300)),再计算一个屏幕分辨率的scale值(((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize)),首先取scale值为这两个scale值中较大的那一个。再然后是一些容错处理,将scale值限制在0~1之间,以防止设备内存小于300MB,同时设备分辨率小于480*800;或者,设备内存大于700MB,或设备分辨率大于1280*800的情况出现时,出现太不合理的阈值。
第129行至133行,是第二轮计算各个adj所对应的minimum free memory阈值。计算各个值的算式为(long)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1])。此处给了各设备对low memory阈值进行定制的机会。各个设备可以在framework的config文件中定义config_lowMemoryKillerMinFreeKbytesAbsolute,以指定最大的adj所对应的free memory阈值,其他各个adj所对应的free memory阈值将依比例算出。
第135行至第142行,是第三轮计算各个adj所对应的minimum free memory阈值。计算各个值的算式为mOomMinFree[i] += (long)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1])。此处是给特定设备微调low memory的阈值提供机会。不过我们仔细来看第二轮和第三轮的计算,这两轮计算似乎是可以合并为****:****(long)((float)(minfree_abs + minfree_adj) * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1])。
后面则是构造适合设置给lowmemorykiller导出参数的字符串,并最终将构造的这组参数设置进去。
那这个ProcessList.updateOomLevels()方法又是在什麽时候会被调用到呢?是在ProcessList.applyDisplaySize()方法中:
1 void applyDisplaySize(WindowManagerService wm) { 2 if (!mHaveDisplaySize) { 3 Point p = new Point(); 4 wm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, p); 5 if (p.x != 0 && p.y != 0) { 6 updateOomLevels(p.x, p.y, true); 7 mHaveDisplaySize = true; 8 } 9 } 10 }
在这个方法中,当能够从WMS中获取有效的屏幕分辨率时,会去更新oom levels,并且更新之后就不会再次去更新。我们再来追查ProcessList.applyDisplaySize(),是在ActivityManagerService.updateConfiguration():
1 public void updateConfiguration(Configuration values) { 2 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, 3 "updateConfiguration()"); 4 5 synchronized(this) { 6 if (values == null && mWindowManager != null) { 7 // sentinel: fetch the current configuration from the window manager 8 values = mWindowManager.computeNewConfiguration(); 9 } 10 11 if (mWindowManager != null) { 12 mProcessList.applyDisplaySize(mWindowManager); 13 } 14 15 final long origId = Binder.clearCallingIdentity(); 16 if (values != null) { 17 Settings.System.clearConfiguration(values); 18 } 19 updateConfigurationLocked(values, null, false, false); 20 Binder.restoreCallingIdentity(origId); 21 } 22 }
我们总结一下OOM levels的更新:时机是在系统启动后,第一个configuration change的消息到AMS的时候;adj值为一组固定的预定义的值;各个adj所对应的min free阈值则根据系统的内存大小和屏幕的分辨率计算得出,各个设备还可以通过framework的config config_lowMemoryKillerMinFreeKbytesAdjust和config_lowMemoryKillerMinFreeKbytesAbsolute来定制最终各个adj所对应的min free阈值。
我们可以根据系统所吐出来的log看一下,事实是否如我们上面对code的分析那样。由某个设备抓到的系统内核吐出来的log,可以发现如下的这些行(只出现一次):
1I/KERNEL ( 609): [ 14.064905] lowmemorykiller: lowmem_shrink: convert oom_adj to oom_score_adj: 2I/KERNEL ( 609): [ 14.064932] lowmemorykiller: oom_adj 0 => oom_score_adj 0 3I/KERNEL ( 609): [ 14.064938] lowmemorykiller: oom_adj 1 => oom_score_adj 58 4I/KERNEL ( 609): [ 14.064942] lowmemorykiller: oom_adj 2 => oom_score_adj 117 5I/KERNEL ( 609): [ 14.064947] lowmemorykiller: oom_adj 3 => oom_score_adj 176 6I/KERNEL ( 609): [ 14.064951] lowmemorykiller: oom_adj 9 => oom_score_adj 529 7I/KERNEL ( 609): [ 14.064956] lowmemorykiller: oom_adj 15 => oom_score_adj 1000
由前面lowmemorykiller的code不难看出,这些log在lowmem_autodetect_oom_adj_values()函数中吐出,是在内核空间吐出来的。吐出这些log的进程的pid为609。我们再来看一下这个进程到底是何方神圣:
1desktop:~/develop_tools$ adb shell ps | grep 609 2system 609 235 1031532 94240 ffffffff ffffe430 S system_server
谜底揭晓,是system_server。不难推测出来,这应当是在系统启动之后,AMS第一次接到configuration change的消息,去更新OOM level,lowmemorykiller的lowmem_autodetect_oom_adj_values()函数被调到,更新lowmemorykiller的lowmem_adj时而吐出来的。与我们前面对AMS code的分析基本一致。
还需要我们厘清的问题,lowmemorykiller的lowmem_shrink具体在什麽时机会被执行?
Done。