Low Memory Killer分析

Chipset: MSM8X25Q

Codebase: Android4.1

Kernel: 3.4.0

 

概念:

         Lowmemory killer是android基于oom killer做了改进。两者区别:

Oom killer: 当系统内存不足时,会根据当前进程的内存使用状况以及oom score来Kill掉某个进程。

Low memorykiller: 会周期性的检查系统内存状况,当系统内存小于其设定的返回时,根据 oom score和当前rss占用内存情况来杀掉进程。

         两者大同小异,不过lowmemory killer概念更简单,直接看代码吧。

         文件路径:android\kernel\drivers\staging\android\Lowmemorykiller.c

初始化:

  1. static int __init lowmem_init(void)  
  2. {  
  3.     /*通过此接口注册之后,系统在内存回收释放时,kswap内核线程会遍历  
  4. Shrinker链表,并调用通过此接口注册的shrink函数。*/  
  5.     register_shrinker(&lowmem_shrinker);  
  6.     return 0;  
  7. }  
  8.   
  9. static struct shrinker lowmem_shrinker = {  
  10.     .shrink = lowmem_shrink,    //核心函数在此!  
  11.     .seeks = DEFAULT_SEEKS * 16  
  12. };  

核心调用:

在说核心函数之前,先了解下lowmemory killer的基础。

它利用lowmem_adj和lowmem_minfree这两个数组来作为评判当前内存不足的标准。如,当前系统空闲内存是63M时,比owmem_minfree[3]小,那么就会选择比lowmem_adj[3]的oom score adj大的进程中找到一个oom score adj最大的将其杀掉,当两个进程的oom score adj一样时,会选择内存占用最多杀掉!数组其他部分以此类推。

  1. static int lowmem_adj[6] = {  
  2.     0,  
  3.     1,  
  4.     6,  
  5.     12,  
  6. };  
  7. static int lowmem_adj_size = 4;  
  8. static int lowmem_minfree[6] = {  
  9.     3 * 512,    /* 6MB */  
  10.     2 * 1024,   /* 8MB */  
  11.     4 * 1024,   /* 16MB */  
  12.     16 * 1024,  /* 64MB */  
  13. };  
  14. static int lowmem_minfree_size = 4;  

lowmem_shrink():

  1. static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)  
  2. {  
  3.     struct task_struct *tsk;  
  4.     struct task_struct *selected = NULL;  
  5.     int rem = 0;  
  6.     int tasksize;  
  7.     int i;  
  8.     int min_score_adj = OOM_SCORE_ADJ_MAX + 1;  
  9.     int selected_tasksize = 0;  
  10.     int selected_oom_score_adj;  
  11.     int array_size = ARRAY_SIZE(lowmem_adj);  
  12.     /*系统总空闲内存数*/  
  13.     int other_free = global_page_state(NR_FREE_PAGES);  
  14.     /*文件和共享内存占用内存数*/  
  15.     int other_file = global_page_state(NR_FILE_PAGES) -  
  16.                         global_page_state(NR_SHMEM);  
  17.     /* 用户空间修改了lowmem_minfree和 lowmem_adj的情况就成立,后面再说*/  
  18.     if (lowmem_adj_size < array_size)  
  19.         array_size = lowmem_adj_size;  
  20.     if (lowmem_minfree_size < array_size)  
  21.         array_size = lowmem_minfree_size;  
  22.     /*遍历当前各种等级下的情况*/  
  23.     for (i = 0; i < array_size; i++) {  
  24.         /*系统总空闲内存或者文件占有内存数比当前设定的lowmem_minfree[i]小,  
  25. 那么就取出相对应的oom score adj作为后面寻找最大oom score adj对应进程的基本  
  26. 标准。*/  
  27.         if (other_free < lowmem_minfree[i] &&  
  28.             other_file < lowmem_minfree[i]) {  
  29.             min_score_adj = lowmem_adj[i];  
  30.             break;  
  31.         }  
  32.     }  
  33.     if (sc->nr_to_scan > 0)  
  34.         lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %d\n",  
  35.                 sc->nr_to_scan, sc->gfp_mask, other_free,  
  36.                 other_file, min_score_adj);  
  37.     rem = global_page_state(NR_ACTIVE_ANON) +  
  38.         global_page_state(NR_ACTIVE_FILE) +  
  39.         global_page_state(NR_INACTIVE_ANON) +  
  40.         global_page_state(NR_INACTIVE_FILE);  
  41.     if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) {  
  42.         lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n",  
  43.                  sc->nr_to_scan, sc->gfp_mask, rem);  
  44.         return rem;  
  45.     }  
  46.     /*暂存,因为后面min_score_adj 会被覆盖。*/  
  47.     selected_oom_score_adj = min_score_adj;  
  48.   
  49.     rcu_read_lock();  
  50.     for_each_process(tsk) {  
  51.         struct task_struct *p;  
  52.         int oom_score_adj;  
  53.         /*kernel thread不能Kill掉。*/  
  54.         if (tsk->flags & PF_KTHREAD)  
  55.             continue;  
  56.         /*处于die状态的进程不管。*/  
  57.         if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {  
  58.             if (test_task_flag(tsk, TIF_MEMDIE)) {  
  59.                 rcu_read_unlock();  
  60.                 return 0;  
  61.             }  
  62.         }  
  63.         /*有mm的thread才能操作*/  
  64.         p = find_lock_task_mm(tsk);  
  65.         if (!p)  
  66.             continue;  
  67.         /*得到task对应的oom_score_adj*/  
  68.         oom_score_adj = p->signal->oom_score_adj;  
  69.         /*比当前的基本标准小就忽略。*/  
  70.         if (oom_score_adj < min_score_adj) {  
  71.             task_unlock(p);  
  72.             continue;  
  73.         }  
  74.         /*获得此进程的rss内存占用大小*/  
  75.         tasksize = get_mm_rss(p->mm);  
  76.         task_unlock(p);  
  77.         if (tasksize <= 0)  
  78.             continue;  
  79.         /*前后两进程开始比较了*/  
  80.         if (selected) {  
  81.             /*如果当前task的oom score比上次小,则不做处理*/  
  82.             if (oom_score_adj < selected_oom_score_adj)  
  83.                 continue;  
  84.             /*如果前后两个task的oom score一样,而且此task 占有  
  85. 内存比上次的task小时,也不做处理。*/  
  86.             if (oom_score_adj == selected_oom_score_adj &&  
  87.                 tasksize <= selected_tasksize)  
  88.                 continue;  
  89.         }  
  90.         /*否则保存oom score和占用内存大小值*/  
  91.         selected = p;  
  92.         selected_tasksize = tasksize;  
  93.         selected_oom_score_adj = oom_score_adj;  
  94.         lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",  
  95.                  p->pid, p->comm, oom_score_adj, tasksize);  
  96.     }  
  97.     if (selected) {  
  98.         lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",  
  99.                  selected->pid, selected->comm,  
  100.                  selected_oom_score_adj, selected_tasksize);  
  101.         lowmem_deathpending_timeout = jiffies + HZ;  
  102.         /*发送SIGKILL信号杀死进程*/  
  103.         send_sig(SIGKILL, selected, 0);  
  104.         set_tsk_thread_flag(selected, TIF_MEMDIE);  
  105.         rem -selected_tasksize;  
  106.     }  
  107.     lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",  
  108.              sc->nr_to_scan, sc->gfp_mask, rem);  
  109.     rcu_read_unlock();  
  110.     return rem;  
  111. }  

lowmem_minfree/lowmem_adj修改:

注意到代码里还有几个函数:

  1. __module_param_call(MODULE_PARAM_PREFIX, adj,  
  2.             &lowmem_adj_array_ops,  
  3.             .arr = &__param_arr_adj,  
  4.             S_IRUGO | S_IWUSR, -1);  
  5. static struct kernel_param_ops lowmem_adj_array_ops = {  
  6.     .set = lowmem_adj_array_set,  
  7.     .get = lowmem_adj_array_get,  
  8.     .free = lowmem_adj_array_free,  
  9. };  
  10.   
  11. static const struct kparam_array __param_arr_adj = {  
  12.     .max = ARRAY_SIZE(lowmem_adj),  
  13.     .num = &lowmem_adj_size,  
  14.     .ops = ¶m_ops_int,  
  15.     .elemsize = sizeof(lowmem_adj[0]),  
  16.     .elem = lowmem_adj,  
  17. };  

这几个函数也比较简单,主要功能是允许用户空间修改lowmem_adj 和lowmem_minfree这两个数组,大家可自行分析。不过要注意的是数组大小最大为6!

         操作这两个数组的文件在:

android\frameworks\base\services\java\com\android\server\am\ProcessList.java

lowmem_adj对应的是mOomAdj数组的值,各个宏表示不同等级的oom score adj.

  1. private final int[] mOomAdj = new int[] {  
  2.     FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,  
  3.     BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, HIDDEN_APP_MAX_ADJ  
  4. };  
通过updateOomLevels函数来修改数组值:
  1. private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {  
  2.         // Scale buckets from avail memory: at 300MB we use the lowest values to  
  3.         // 700MB or more for the top values.  
  4.         float scaleMem = ((float)(mTotalMemMb-300))/(700-300);  
  5.   
  6.         // Scale buckets from screen size.  
  7.         int minSize = 320*480;  //  153600  
  8.         int maxSize = 1280*800; // 1024000  230400 870400  .264  
  9.         float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);  
  10.         //Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth + " dh=" + displayHeight);  
  11.   
  12.         StringBuilder adjString = new StringBuilder();  
  13.         StringBuilder memString = new StringBuilder();  
  14.   
  15.         float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;  
  16.         if (scale < 0scale = 0;  
  17.         else if (scale > 1) scale = 1;  
  18.         /*分辨率的不同会影响当前设定的lowmem_minfree。*/  
  19.         for (int i=0; i<mOomAdj.length; i++) {  
  20.             long low = mOomMinFreeLow[i];  
  21.             long high = mOomMinFreeHigh[i];  
  22.             mOomMinFree[i] = (long)(low + ((high-low)*scale));  
  23.   
  24.             if (i > 0) {  
  25.                 adjString.append(',');  
  26.                 memString.append(',');  
  27.             }  
  28.             adjString.append(mOomAdj[i]);  
  29.             memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);  
  30.         }  
  31.         Slog.e("Kris", "******************************* MINFREE: " + memString);  
  32.         if (write) {  
  33.             /*写进kernel~*/  
  34.             writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());  
  35.             writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());  
  36.         }  
  37.         // GB: 2048,3072,4096,6144,7168,8192  
  38.         // HC: 8192,10240,12288,14336,16384,20480  
  39. }  
  40.   
  41.  // These are the low-end OOM level limits.  This is appropriate for an  
  42.  // HVGA or smaller phone with less than 512MB.  Values are in KB.  
  43.     private final long[] mOomMinFreeLow = new long[] {  
  44.             8192, 12288, 16384,  
  45.             24576, 28672, 32768  
  46.     };  
  47.     // These are the high-end OOM level limits.  This is appropriate for a  
  48.     // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.  
  49.     private final long[] mOomMinFreeHigh = new long[] {  
  50.             32768, 40960, 49152,  
  51.             57344, 65536, 81920  
  52.     }; 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值