<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Android Low Memory Killer

      Low Memory Killer的原理

        在Android中,即使當(dāng)用戶退出應(yīng)用程序之后,應(yīng)用程序的進(jìn)程也還是存在于系統(tǒng)中,這樣是為了方便程序的再次啟動(dòng),但是這樣的話,隨著打開的程序數(shù)量的增加,系統(tǒng)的內(nèi)存會(huì)變得不足,就需要?dú)⒌粢徊糠诌M(jìn)程以釋放內(nèi)存空間。至于是否需要?dú)⑺酪恍┻M(jìn)程和哪些進(jìn)程需要被殺死,是通過Low Memory Killer機(jī)制來進(jìn)行判定的。

        Android的Low Memory Killer基于Linux的OOM機(jī)制,在Linux中,內(nèi)存是以頁面為單位分配的,當(dāng)申請頁面分配時(shí)如果內(nèi)存不足會(huì)通過以下流程選擇bad進(jìn)程來殺掉從而釋放內(nèi)存:

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

        在Low Memory Killer中通過進(jìn)程的oom_adj與占用內(nèi)存的大小決定要?dú)⑺赖倪M(jìn)程,oom_adj越小越不容易被殺死。

        Low Memory Killer Driver在用戶空間指定了一組內(nèi)存臨界值及與之一一對(duì)應(yīng)的一組oom_adj值,當(dāng)系統(tǒng)剩余內(nèi)存位于內(nèi)存臨界值中的一個(gè)范圍內(nèi)時(shí),如果一個(gè)進(jìn)程的oom_adj值大于或等于這個(gè)臨界值對(duì)應(yīng)的oom_adj值就會(huì)被殺掉。

        可以通過修改/sys/module/lowmemorykiller/parameters/minfree與/sys/module/lowmemorykiller/parameters/adj來改變內(nèi)存臨界值及與之對(duì)應(yīng)的oom_adj值。minfree中數(shù)值的單位是內(nèi)存中的頁面數(shù)量,一般情況下一個(gè)頁面是4KB。
        比如如果向/sys/module/lowmemorykiller/parameters/adj寫入0,8,向/sys/module/lowmemorykiller/parameters/minfree中寫入1024,4096,假設(shè)一個(gè)頁面大小為4KB,這樣當(dāng)系統(tǒng)空閑內(nèi)存位于1024*4~4096*4KB之間時(shí)oom_adj大于等于8的進(jìn)程就會(huì)被殺掉。

        在lowmemorykiller.c中定義了閾值表的默認(rèn)值,可以通過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進(jìn)程的oom_adj為-16,不可能會(huì)被殺死(init的PID是1):

      on early-init
          # Set init and its forked children's oom_adj.
          write /proc/1/oom_adj -16

        在Linux中有一個(gè)kswapd的內(nèi)核線程,當(dāng)linux回收內(nèi)存分頁的時(shí)候,kswapd線程將會(huì)遍歷一張shrinker鏈表,并執(zhí)行回調(diào),定義如下:

      
      
      /*
       * 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鏈表中添加或移除回調(diào)。當(dāng)注冊Shrinker后就可以在回收內(nèi)存分頁時(shí)按自己定義的規(guī)則釋放內(nèi)存。

        Android Low Memory Killer的代碼在drivers/staging/android/lowmemorykiller.c中,通過以下代碼在模塊初始化時(shí)注冊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);

        這樣就可以在回收內(nèi)存分頁時(shí)調(diào)用lowmem_shrink函數(shù)。

      Low Memory Killer的實(shí)現(xiàn)

        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;
      }
      View Code

        分開來看這段代碼,首先取得內(nèi)存閾值表的大小,取閾值表數(shù)組大小與lowmem_adj_size,lowmem_minfree_size的較小值,然后通過globa_page_state獲得當(dāng)前剩余內(nèi)存的大小,然后跟內(nèi)存閾值表中的閾值相比較獲得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;

        遍歷所有進(jìn)程找到oom_adj>min_adj并且占用內(nèi)存大的進(jìn)程:

      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,即超過警戒值
          //獲取內(nèi)存占用大小,若<=0,不做處理
          tasksize = get_mm_rss(mm);
          task_unlock(p);
          if (tasksize <= 0)
              continue;
          //如果之前已經(jīng)先擇了一個(gè)進(jìn)程,比較當(dāng)前進(jìn)程與之前選擇的進(jìn)程的oom_adj與內(nèi)存占用大小,如果oom_adj比之前選擇的小或相等而內(nèi)存占用比之前選擇的進(jìn)程小,不做處理。
          if (selected) {
              if (oom_adj < selected_oom_adj)
                  continue;
              if (oom_adj == selected_oom_adj &&
                  tasksize <= selected_tasksize)
                  continue;
          }
          //走到這里表示當(dāng)前進(jìn)程比之前選擇的進(jìn)程oom_adj大或相等但占用內(nèi)存大,選擇當(dāng)前進(jìn)程
          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);
      }

        如果選擇出了符合條件的進(jìn)程,發(fā)送SIGNAL信號(hào)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的關(guān)系

        我們知道,在上層進(jìn)程按重要性可以分為:Foreground process,Visible process,Service process,Background process與Empty process,那么這些重要性怎么與Low Memory Killer中的oom_adj對(duì)應(yīng)起來的呢?

        在ActivityManager.RunningAppProcessInfo中我們可以看到如下關(guān)于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等級(jí),而在ProcessList中我們會(huì)發(fā)現(xiàn)關(guān)于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的等級(jí)都是相同的。

        關(guān)于ADJ與Importance的值都找到了,那么它們是怎么對(duì)應(yīng)起來的呢?Activity實(shí)際是由ActivityManagerService來管理的,在ActivityManagerService中我們可以找到以下函數(shù):

      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;
          }
      }

        在這個(gè)函數(shù)中實(shí)現(xiàn)了根據(jù)adj設(shè)置importance的功能。

        我們還可以看到SERVICE還分為SERVICE_B_ADJ與SERVICE_ADJ,等級(jí)是不一樣的,并不是所有Service的優(yōu)先級(jí)都比Background process的優(yōu)先級(jí)高。當(dāng)調(diào)用Service的startForeground后,Service的importance就變?yōu)榱薎MPORTANCE_PERCEPTIBLE(在記憶中曾經(jīng)將Service設(shè)置為foreground并打印出其importance的值與IMPORTANCE_PERCEPTIBLE相等),對(duì)應(yīng)的adj是PERCEPTIBLE_APP_ADJ,即2,已經(jīng)很難被系統(tǒng)殺死了。

      // 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;

        像電話等進(jìn)程的adj為-12已基本不可能被殺死了,而在前面已經(jīng)看到了,init.rc中將init進(jìn)程的oom_adj設(shè)置為了-16,已經(jīng)是永生進(jìn)程了。

       

      相關(guān)鏈接:

      lowermemorykiller.txt

      lowermemorykiller.c

      shrinker_list

      posted @ 2013-05-21 16:38  AngelDevil  閱讀(27096)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲av色夜色精品一区| 亚洲AV午夜成人无码电影| 久久国产免费观看精品3| 亚洲欧美综合人成在线| 军人粗大的内捧猛烈进出视频| 亚洲色欲色欱WWW在线| 久久久久无码精品亚洲日韩| 丰满的人妻hd高清日本| 最新国产精品亚洲| 日本熟妇浓毛hdsex| 国产老熟女国语免费视频| 亚洲精品成人区在线观看| 熟女一区| 色欲国产精品一区成人精品| 国产成人一区二区三区免费| 国产日韩av二区三区| 日本高清一区免费中文视频| 天堂网亚洲综合在线| 军人粗大的内捧猛烈进出视频| 亚洲国产精品男人的天堂| 99在线精品视频观看免费| 国产边打电话边被躁视频| 亚洲欧洲日产国无高清码图片 | 国产精品熟妇视频国产偷人| 性色a码一区二区三区天美传媒| 蜜臀久久精品亚洲一区| 亚洲男人第一无码av网| 天堂在线精品亚洲综合网| 国产亚洲欧美日韩在线一区二区三 | 天天澡日日澡狠狠欧美老妇| 景东| 久久亚洲精品人成综合网| 在线看无码的免费网站| 中文字幕av无码免费一区| 亚洲国产精品高清久久久| 国产精品露脸3p普通话| 国产av午夜精品福利| 亚洲中文字幕精品一区二区三区| 成人动漫综合网| 国产精品有码在线观看| 久久夜色精品国产亚洲a|