Chinaunix首页 | 论坛 | 博客
  • 博客访问: 261929
  • 博文数量: 63
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1860
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-07 14:41
文章分类

全部博文(63)

文章存档

2015年(2)

2014年(61)

我的朋友

分类: Android平台

2014-10-07 15:51:30

清单 6. 执行 destroyActivityLocked() 销毁

  1. boolean canQuit = !app.persistent && app.curReceiver == null
  2. && app.services.size() == 0
  3.     && app.persistentActivities == 0;
  4. int NUMA = app.activities.size();
  5. for (j=0; j
  6.     HistoryRecord r = (HistoryRecord)app.activities.get(j);
  7.     canQuit = (r.haveState || !r.stateNotNeeded)
  8.             && !r.visible && r.stopped;
  9. }
  10. if (canQuit) {
  11.     // Finish all of the activities, and then the app itself.
  12.     for (j=0; j
  13.         HistoryRecord r = (HistoryRecord)app.activities.get(j);
  14.         if (!r.finishing) {
  15.             destroyActivityLocked(r, false);
  16.         }
  17.         r.resultTo = null;
  18.     }
  19.     if (app.pid > 0 && app.pid != MY_PID) {
  20.         Process.killProcess(app.pid);
  21.     }
  22.     cleanUpApplicationRecordLocked(app, false, i);
  23.     i--;
  24.     //dump();
  25. }
复制代码

    步骤四,上面 3 个过程都是针对整个 process 进行的资源回收。在以上过程执行完毕之后,将在更小的粒度上对 Activity 的资源进行回收。与上面所述类似,列表 mLRUActivities 存储了当前所有运行中的 Activity,排序规则同样为最少访问原则。mLRUActivities.size() 返回系统中运行的 Activity 的数量,当其大于 MAX_ACTIVITIES(MAX_ACTIVITIES 是一个常量,一般值为 20,代表系统中最大允许同时存在的 Activity)时。将回收部分满足条件的 Activity 以减少内存的使用。回收条件代码清单 7 所示:

清单 7. 回收条件代码

  1. //Finally, if there are too many activities now running, try to
  2. // finish as many as we can to get back down to the limit.
  3. for (   i=0;
  4.         i
  5.             && mLRUActivities.size()  > curMaxActivities;
  6.         i++) {
  7. final HistoryRecord r
  8.         = (HistoryRecord)mLRUActivities.get(i); 

  9.     // We can finish this one if we have its icicle saved and
  10.     // it is not persistent.
  11.     if ((r.haveState || !r.stateNotNeeded) && !r.visible
  12.             && r.stopped && !r.persistent && !r.finishing) {
  13.         final int origSize = mLRUActivities.size();
  14.         destroyActivityLocked(r, true);
  15.         if (origSize  > mLRUActivities.size()) {
  16.             i--;
  17.         }
  18.     }
  19. }
复制代码

     这里回收的只是 Activity 的内存资源,并不会杀死进程,也不会影响进程的运行。当进程需要调用被杀掉的 Activity 时,可以从保存的状态中回复,当然可能需要相对长一点的时延。

Linux 内核中的内存回收

lowmemorykiller

     上面提到,trimApplications() 函数中会执行一个叫做 updateOomAdjLocked() 的函数,如果返回 false,则执行默认回收,若返回 true 则不执行默认内存回收。updateOomAdjLocked 将针对每一个进程更新一个名为 adj 的变量,并将其告知 Linux 内核,内核维护一个包含 adj 的数据结构(即进程表),并通过 lowmemorykiller 检查系统内存的使用情况,在内存不足的情况下杀死一些进程并释放内存。下面将对这种 Android Framework 与 Linux 内核相配合的内存回收机制进行研究。

     由于 Android 操作系统中的所有应用程序都运行在独立的 Dalvik 虚拟机环境中,Linux 内核无法获知每个进程的运行状态,也就无法为每个进程维护一个合适的 adj 值,因此,Android Application Framework 中必须提供一套机制以动态的更新每个进程的 adj。这就是 updateOomAdjLocked()。

     updateOomAdjLocked() 位于 ActivityManagerService 中,其主要作用是为进程选择一个合适的 adj 值,并通知 Linux 内核更新这个值。updateOomAdjLocked 首先调用 computeOomAdjLocked() 初步计算 adj 的值,然后回到 updateOomAdjLocked() 对其值进行进一步修正。估算流程可参见代码。

     关于 adj,其定义在 task_struct->signal_struct->adj, 文件 /kernel/include/linux/sched.h 中。实质为进程数据结构中的一个变量,用来表示发生 Out of Memory 时杀死进程的优先级顺序。lowmemorykiller 利用这个变量对进程的重要程度进行判断,并在内存不足时释放部分空间,其实现在文件 /kernel/drivers/staging/android/lowmemorykiller.c 中。lowmemorykiller 定义了两个数组:lowmem_adj 和 lowmem_minfree。其中 lowmen_adj 定义了一系列 adj 键值,而 lowmem_minfree 的每个元素代表一个内存阈值。如下代码中四个阈值分别是 6MB,8MB,16MB 和 64MB,分别代表当内存小于 64MB 时,adj 大于或等于 12 的那些进程将被杀死并回收,内存小于 16MB 时,adj 大于等于 6 的那些进程将被杀死并回收,内存小于 8MB 时,adj 大于等于 1 的那些进程将被杀死并回收,内存小于 6MB 时,adj 大于等于 0 的所有进程将被杀死并回收。内核中的每个进程都持有一个 adj,取值范围 -17 到 15,值越小代表进程的重要性越高,回收优先级越低,其中 -17 代表禁用自动回收。Android 系统中,只有 0-15 被使用。

清单 8. 每个进程都持有一个 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 size_t 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;
复制代码

    lowmemorykiller 注册一个 lowmem_shrinker,lowmem_shrinker 利用了标准 Linux 内核中的 Cache Shrinker 来实现,当空闲内存页面不足时,内核线程 kswapd 将用已注册的 lowmem_shrinker 来回收内存页面。

清单 9. 用已注册的 lowmem_shrinker 来回收内存页面

  1. static struct shrinker lowmem_shrinker = {
  2.                    .shrink = lowmem_shrink,
  3.        .seeks = DEFAULT_SEEKS * 16
  4. }; 

  5. static int __init lowmem_init(void)
  6. {
  7.        task_free_register(&task_nb);
  8.        register_shrinker(&lowmem_shrinker);
  9.        return 0;
  10. }
复制代码

     lowmem_shrink 的代码在函数 lowmem_shrink 中,下面给出该函数的主要结构。lowmem_shrink 根据上述规则遍历所有进程,选出需要结束的进程,通过发送一个无法忽略的信号 SIGKILL 强制结束这些进程

清单 10. 强制结束进程

  1. static int lowmem_shrink(struct shrinker *s, int nr_to_scan, gfp_t gfp_mask)
  2. {
  3.         for_each_process(p) {
  4.            //Select processes to be forced
  5.         }
  6.         if (selected) {
  7.                force_sig(SIGKILL, selected);
  8.                rem -= selected_tasksize;
  9.         } else
  10.         rem = -1;
  11.         return rem;
  12. }
复制代码

Oom_killer.

      如果上述各种方法都无法释放出足够的内存空间,那么当为新的进程分配应用程序时将发生 Out of Memory 异常,OOM_killer 将尽最后的努力杀掉一些进程来释放空间。Android 中的 OOM_killer 继承自标准 Linux 2.6 内核,用于分配内存时 Out of Memory 的处理。Android 并没有对其实现方式进行修改。其位置在 linux/mm/oom_kill.c。 oom_killer 遍历进程,并计算所有进程的 badness 值,选择 badness 最大的那个进程将其杀掉。函数 badness 的声明如下:

unsigned long badness(struct task_struct *p, unsigned long uptime) 函数 select_bad_process 返回将要杀掉的那个进程。

清单 11. 返回将要杀掉的进程

  1. static struct task_struct *select_bad_process(unsigned long *ppoints,
  2.                                            struct mem_cgroup *mem)
  3. {
  4.        for_each_process(p) {
  5.               points = badness(p, uptime.tv_sec);
  6.               if (points > *ppoints || !chosen) {
  7.                       chosen = p;
  8.                       *ppoints = points;
  9.               }
  10.        }
  11.        return chosen;
  12. }
复制代码

最后,和 lowmemorykiller 一样,通过发送 SIGKILL 结束选中的进程。由于 oom_killer 与标准 Linux 内核并无不同,这里不再详细研究。

总结

    本文研究了 Android 操作系统上的内存回收机制。主要包括 Application Framework 层的默认回收以及 Linux 内核中的 lowmemorykiller、OOM_killer。一般来说应用开发者并不需要控制或者修改系统的内存管理以及回收,但是深入理解这些系统级的管理机制还是必要的,尤其有助于更加合理地设计应用程序,使应用程序的进程在其生命周期内高效地运行。而系统级开发者如果想要对内存管理机制进行优化,对原有机制的理解则是必不可少的重要前提。

阅读(687) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~