Android内存管理机制详解

来源:互联网 发布:大数据的意义包括 多选 编辑:程序博客网 时间:2024/05/17 07:22

android内存的意义

        其实我们在用安卓手机的时候不用太在意剩余内存,Android上的应用是java,当然需要虚拟机,而android上的应用是带有独立虚拟机的,也就是每开一个应用就会打开一个独立的虚拟机。其实和java的垃圾回收机制类似(原理类似Java的引用),系统有一个规则来回收内存。进行内存调度有个阀值,只有低于这个值系统才会按一个列表来关闭用户不需要的东西。当然这个值默认设置得很小,所以你会看到内存老在很少的数值徘徊。但事实上他并不影响速度。相反加快了下次启动应用的速度。这本来就是 android标榜的优势之一,如果人为去关闭进程,没有太大必要。特别是使用自动关进程的软件。为什么内存少的时候运行大型程序会慢呢,原因是:在内存剩余不多时打开大型程序时会触发系统自身的调进程调度策略,这是十分消耗系统资源的操作,特别是在一个程序频繁向系统申请内存的时候。这种情况下系统并不会关闭所有打开的进程,而是选择性关闭,频繁的调度自然会拖慢系统。

 

进程管理软件

        进程管理软件有无必要呢?有的。就是在运行大型程序之前,你可以手动关闭一些进程释放内存,可以显著的提高运行速度。但一些小程序完全可交由系统自己管理。那么如果不关程序是不是会更耗电。android的应用在被切换到后台时,它其实已经被暂停了,并不会消耗cpu资源只保留了运行状态。所以为什么有的程序切出去重进会到主界面。但是一个程序如果想要在后台处理些东西,如音乐播放,它就会开启一个服务。服务可在后台持续运行,所以在后台耗电的也只有带服务的应用了。我们可以把带服务的进程用进程管理软件关闭就可以了。没有带服务的应用在后台是完全不耗电的没有必要关闭。这种设计本来就是一个非常好的设计,下次启动程序时会更快,因为不需要读取界面资源,何必要关掉他们抹杀这个android的优点呢。

Android进程种类

注:决定APP进程的级别,内存分配有Android系统执行,所以App本身不能修改级别,只能通过裁剪Android系统时修改代码,才能修改分配到App各个级别的内存。

1.       前台进程(foreground

        目前正在屏幕上显示的进程和一些系统进程。举例来说,DialerStorageGoogle Search等系统进程就是前台进程;再举例来说,当你运行一个程序,如浏览器,当浏览器界面在前台显示时,浏览器属于前台进程(foreground),但一旦你按home回到主界面,浏览器就变成了后台程序(background)。我们最不希望终止的进程就是前台进程。

2.       可见进程(visible

        可见进程是一些不再前台,但用户依然可见的进程,举个例来说:widget、输入法等,都属于visible。这部分进程虽然不在前台,但与我们的使用也密切相关,我们也不希望它们被终止(你肯定不希望时钟、天气,新闻等widget被终止,那它们将无法同步,你也不希望输入法被终止,否则你每次输入时都需要重新启动输入法)

3.       桌面进程(home app

        即launcher,保证在多任务切换之后,可以快速返回到home界面而不需重新加载launcher

4.       次要服务(secondary server

        目前正在运行的一些服务(主要服务,如拨号等,是不可能被进程管理终止的,故这里只谈次要服务),举例来说:谷歌企业套件,Gmail内部存储,联系人内部存储等。这部分服务虽然属于次要服务,但跟一些系统功能依然息息相关,我们时常需要用到它们,所以也不太希望他们被终止

5.       后台进程(hidden

        即是后台进程(background),就是我们通常意义上理解的启动后被切换到后台的进程,如浏览器,阅读器等。当程序显示在屏幕上时,他所运行的进程即为前台进程(foreground),一旦我们按home返回主界面(注意是按home,不是按back),程序就驻留在后台,成为后台进程(background)。后台进程的管理策略有多种:有较为积极的方式,一旦程序到达后台立即终止,这种方式会提高程序的运行速度,但无法加速程序的再次启动;也有较消极的方式,尽可能多的保留后台程序,虽然可能会影响到单个程序的运行速度,但在再次启动已启动的程序时,速度会有所提升。这里就需要用户根据自己的使用习惯找到一个平衡点

6.       内容供应节点(content provider

        没有程序实体,进提供内容供别的程序去用的,比如日历供应节点,邮件供应节点等。在终止进程时,这类程序应该有较高的优先权

7.       空进程(empty

        没有任何东西在内运行的进程,有些程序,比如BTE,在程序退出后,依然会在进程中驻留一个空进程,这个进程里没有任何数据在运行,作用往往是提高该程序下次的启动速度或者记录程序的一些历史信息。这部分进程无疑是应该最先终止的。

幽灵刽子手LMK (Low Memory Killer)

 

执行条件

        剩余内存小于应用定义的APP_MEM值,开始查看adj值列表,kill相应程序。

实现机制

Low Memory Killer的源代码在kernel/drivers/staging/android/lowmemorykiller.c

[cpp]view plaincopyprint?
  1. module_init(lowmem_init);  
  2.   
  3. module_exit(lowmem_exit);  
module_init(lowmem_init);module_exit(lowmem_exit);

    模块加载和退出的函数,主要的功能就是register_shrinker和unregister_shrinker结构体lowmem_shrinker。主要是将函数lowmem_shrink注册到shrinker链表里,在mm_scan调用。

下面详细的介绍这个函数:

[cpp]view plaincopyprint?
  1. for (i = 0; i < array_size; i++) {  
  2.         if (other_file < lowmem_minfree[i]) {  
  3.             min_adj = lowmem_adj[i];  
  4.             break;  
  5.         }  
  6.     }  
for (i = 0; i < array_size; i++) {        if (other_file < lowmem_minfree[i]) {            min_adj = lowmem_adj[i];            break;        }    }

other_file 系统的空闲内存数,根据上面的逻辑判断出,low memory killer需要对adj高于多少(min_adj)的进程进行分析是否释放。

[cpp]view plaincopyprint?
  1. if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) {  
  2.        lowmem_print(5, "lowmem_shrink %d, %x, return %d\n",  
  3.                 nr_to_scan, gfp_mask, rem);  
  4.        return rem;  
  5.    }  
 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;    }

  判断,系统当前的状态是否需要进行low memory killer。

[cpp]view plaincopyprint?
  1. for_each_process(p) {  
  2.         struct mm_struct *mm;  
  3.         struct signal_struct *sig;  
  4.         int oom_adj;  
  5.         task_lock(p);  
  6.         mm = p->mm;  
  7.         sig = p->signal;  
  8.         if (!mm || !sig) {  
  9.             task_unlock(p);  
  10.             continue;  
  11.         }  
  12.         oom_adj = sig->oom_adj;  
  13.         if (oom_adj < min_adj) {  
  14.             task_unlock(p);  
  15.             continue;  
  16.         }  
  17.         tasksize = get_mm_rss(mm);  
  18.         task_unlock(p);  
  19.         if (tasksize <= 0)  
  20.             continue;  
  21.         if (selected) {  
  22.             if (oom_adj < selected_oom_adj)  
  23.                 continue;  
  24.             if (oom_adj == selected_oom_adj &&  
  25.                 tasksize <= selected_tasksize)  
  26.                 continue;  
  27.         }  
  28.         selected = p;  
  29.         selected_tasksize = tasksize;  
  30.         selected_oom_adj = oom_adj;  
  31.         lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",  
  32.                  p->pid, p->comm, oom_adj, tasksize);  
  33.     }  
for_each_process(p) {        struct mm_struct *mm;        struct signal_struct *sig;        int oom_adj;        task_lock(p);        mm = p->mm;        sig = p->signal;        if (!mm || !sig) {            task_unlock(p);            continue;        }        oom_adj = sig->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);    }

对每个sig->oom_adj大于min_adj的进程,找到占用内存最大的进程存放在selected中。

[cpp]view plaincopyprint?
  1. if (selected) {  
  2.         if (fatal_signal_pending(selected)) {  
  3.             pr_warning("process %d is suffering a slow death\n",  
  4.                    selected->pid);  
  5.             read_unlock(&tasklist_lock);  
  6.             return rem;  
  7.         }  
  8.         lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",  
  9.                  selected->pid, selected->comm,  
  10.                  selected_oom_adj, selected_tasksize);  
  11.         force_sig(SIGKILL, selected);  
  12.         rem -= selected_tasksize;  
  13.     }  
if (selected) {        if (fatal_signal_pending(selected)) {            pr_warning("process %d is suffering a slow death\n",                   selected->pid);            read_unlock(&tasklist_lock);            return rem;        }        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;    }

发送SIGKILL信息,杀掉该进程。

        在了解了其机制和原理之后,我们发现它的实现非常简单,与标准的Linux OOM机制类似,只是实现方式稍有不同。标准LinuxOOM Killer机制在mm/oom_kill.c中实现,且会被__alloc_pages_may_oom调用(在分配内存时,即mm/page_alloc.c)oom_kill.c最主要的一个函数是out_of_memory,它选择一个bad进程KillKill的方法同样是通过发送SIGKILL信号。在out_of_memory中通过调用select_bad_process来选择一个进程Kill,选择的依据在badness函数中实现,基于多个标准来给每个进程评分,评分最高的被选中并Kill。一般而言,占用内存越多,oom_adj就越大,也就越有可能被选中。

资源配置

阈值表可以通过/sys/module/lowmemorykiller/parameters/adj/sys/module/lowmemorykiller/parameters/minfree进行配置,例如在init.rc中:

[plain]view plaincopyprint?
  1. # Write value must be consistent with the above properties.  
  2.   
  3.    write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15  
  4.    write /proc/sys/vm/overcommit_memory 1  
  5.    write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144  
  6.   
  7.    class_start default  
# Write value must be consistent with the above properties.   write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15   write /proc/sys/vm/overcommit_memory 1   write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144   class_start default

进程oom_adj同样可以进行设置,通过write /proc/<PID>/oom_adj ,在init.rc中,init进程的pid1omm_adj被配置为-16,永远不会被杀死。

[plain]view plaincopyprint?
  1. # Set init its forked children's oom_adj.  
  2.   
  3.   write /proc/1/oom_adj -16  
 # Set init its forked children's oom_adj.   write /proc/1/oom_adj -16

     Low memory killer的基本原理我们应该弄清了,正如我前面所说的,进程omm_adj的大小跟进程的类型以及进程被调度的次序有关。进程的类型,可以在ActivityManagerService中清楚的看到:

[java]view plaincopyprint?
  1. static final int EMPTY_APP_ADJ;  
  2. static final int HIDDEN_APP_MAX_ADJ;  
  3. static final int HIDDEN_APP_MIN_ADJ;  
  4. static final int HOME_APP_ADJ;  
  5. static final int BACKUP_APP_ADJ;  
  6. static final int SECONDARY_SERVER_ADJ;  
  7. static final int HEAVY_WEIGHT_APP_ADJ;  
  8. static final int PERCEPTIBLE_APP_ADJ;  
  9. static final int VISIBLE_APP_ADJ;  
  10. static final int FOREGROUND_APP_ADJ;  
  11. static final int CORE_SERVER_ADJ = -12;  
  12. static final int SYSTEM_ADJ = -16;<SPAN style="FONT-FAMILY: Calibri; FONT-SIZE: 14px"></SPAN>  
    static final int EMPTY_APP_ADJ;    static final int HIDDEN_APP_MAX_ADJ;    static final int HIDDEN_APP_MIN_ADJ;    static final int HOME_APP_ADJ;    static final int BACKUP_APP_ADJ;    static final int SECONDARY_SERVER_ADJ;    static final int HEAVY_WEIGHT_APP_ADJ;    static final int PERCEPTIBLE_APP_ADJ;    static final int VISIBLE_APP_ADJ;    static final int FOREGROUND_APP_ADJ;    static final int CORE_SERVER_ADJ = -12;    static final int SYSTEM_ADJ = -16;

  ActivityManagerService定义各种进程的oom_adj,CORE_SERVER_ADJ代表一些核心的服务的omm_adj,数值为-12,由前面的分析可知道,这类进程永远也不会被杀死。

在init.rc中: 

[plain]view plaincopyprint?
  1. # Define the oom_adj values for the classes of processes that can be  
  2. # killed by the kernel.  These are used in ActivityManagerService.  
  3.     setprop ro.FOREGROUND_APP_ADJ 0  
  4.     setprop ro.VISIBLE_APP_ADJ 1  
  5.     setprop ro.HOME_APP_ADJ 1  
  6.     setprop ro.PERCEPTIBLE_APP_ADJ 2  
  7.     setprop ro.HEAVY_WEIGHT_APP_ADJ 3  
  8.     setprop ro.SECONDARY_SERVER_ADJ 4  
  9.     setprop ro.BACKUP_APP_ADJ 5  
  10.     setprop ro.HIDDEN_APP_MIN_ADJ 7  
  11.     setprop ro.EMPTY_APP_ADJ 15  
  12.   
  13. # Define the memory thresholds at which the above process classes will  
  14. # be killed.  These numbers are in pages (4k).  
  15.     setprop ro.FOREGROUND_APP_MEM 2048  
  16.     setprop ro.VISIBLE_APP_MEM 3072  
  17.     setprop ro.HOME_APP_MEM 3072  
  18.     setprop ro.PERCEPTIBLE_APP_MEM 4096  
  19.     setprop ro.HEAVY_WEIGHT_APP_MEM 4096  
  20.     setprop ro.SECONDARY_SERVER_MEM 10240  
  21.     setprop ro.BACKUP_APP_MEM 10240  
  22.     setprop ro.HIDDEN_APP_MEM 10240  
  23.     setprop ro.EMPTY_APP_MEM 14336  
  24.   
  25. # Write value must be consistent with the above properties.  
  26. # Note that the driver only supports 6 slots, so we have combined some of  
  27. # the classes into the same memory level; the associated processes of higher  
  28. # classes will still be killed first.  
  29.     write /sys/module/lowmemorykiller/parameters/adj 0,1,2,4,7,15  
  30.   
  31.     write /proc/sys/vm/overcommit_memory 1  
  32.     write /proc/sys/vm/min_free_order_shift 4  
  33.   write /sys/module/lowmemorykiller/parameters/minfree 2048,3072,4096,10240,10240,14336  
  34.   
  35.     # Set init its forked children's oom_adj.  
  36.     write /proc/1/oom_adj -16  
# Define the oom_adj values for the classes of processes that can be# killed by the kernel.  These are used in ActivityManagerService.    setprop ro.FOREGROUND_APP_ADJ 0    setprop ro.VISIBLE_APP_ADJ 1    setprop ro.HOME_APP_ADJ 1    setprop ro.PERCEPTIBLE_APP_ADJ 2    setprop ro.HEAVY_WEIGHT_APP_ADJ 3    setprop ro.SECONDARY_SERVER_ADJ 4    setprop ro.BACKUP_APP_ADJ 5    setprop ro.HIDDEN_APP_MIN_ADJ 7    setprop ro.EMPTY_APP_ADJ 15# Define the memory thresholds at which the above process classes will# be killed.  These numbers are in pages (4k).    setprop ro.FOREGROUND_APP_MEM 2048    setprop ro.VISIBLE_APP_MEM 3072    setprop ro.HOME_APP_MEM 3072    setprop ro.PERCEPTIBLE_APP_MEM 4096    setprop ro.HEAVY_WEIGHT_APP_MEM 4096    setprop ro.SECONDARY_SERVER_MEM 10240    setprop ro.BACKUP_APP_MEM 10240    setprop ro.HIDDEN_APP_MEM 10240    setprop ro.EMPTY_APP_MEM 14336# Write value must be consistent with the above properties.# Note that the driver only supports 6 slots, so we have combined some of# the classes into the same memory level; the associated processes of higher# classes will still be killed first.    write /sys/module/lowmemorykiller/parameters/adj 0,1,2,4,7,15    write /proc/sys/vm/overcommit_memory 1    write /proc/sys/vm/min_free_order_shift 4  write /sys/module/lowmemorykiller/parameters/minfree 2048,3072,4096,10240,10240,14336    # Set init its forked children's oom_adj.    write /proc/1/oom_adj -16

ActivityManagerService.java

打开程序或者有程序进入后台时都会执行updateOomAdjLocked()函数:

[java]view plaincopyprint?
  1. final boolean updateOomAdjLocked() {  
  2.        boolean didOomAdj = true;  
  3.        final ActivityRecord TOP_ACT = resumedAppLocked();  
  4.        final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;  
  5.   
  6.        if (false) {  
  7.            RuntimeException e = new RuntimeException();  
  8.            e.fillInStackTrace();  
  9.            Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);  
  10.        }  
  11.   
  12.        mAdjSeq++;  
  13.   
  14.        // Let's determine how many processes we have running vs.   
  15.        // how many slots we have for background processes; we may want   
  16.        // to put multiple processes in a slot of there are enough of   
  17.        // them.   
  18.        int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;  
  19.        int factor = (mLruProcesses.size()-4)/numSlots;  
  20.        if (factor < 1) factor = 1;  
  21.        int step = 0;  
  22.        int numHidden = 0;  
  23.          
  24.        // First try updating the OOM adjustment for each of the   
  25.        // application processes based on their current state.   
  26.        int i = mLruProcesses.size();  
  27.        int curHiddenAdj = HIDDEN_APP_MIN_ADJ;  
  28.  while (i > 0) {  
  29.            i--;  
  30.            ProcessRecord app = mLruProcesses.get(i);  
  31.            //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);   
  32.            if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {  
  33.                if (curHiddenAdj < EMPTY_APP_ADJ  
  34.                    && app.curAdj == curHiddenAdj) {  
  35.                    step++;  
  36.                    if (step >= factor) {  
  37.                        step = 0;  
  38.                        curHiddenAdj++;  
  39.                    }  
  40.                }  
  41.                if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {  
  42.                    if (!app.killedBackground) {  
  43.                        numHidden++;  
  44.                        if (numHidden > MAX_HIDDEN_APPS) {  
  45.                            Slog.e(TAG, "No longer want " + app.processName  
  46.                                    + " (pid " + app.pid + "): hidden #" + numHidden);  
  47.                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,  
  48.                                    app.processName, app.setAdj, "too many background");  
  49.                            app.killedBackground = true;  
  50.                            Process.killProcessQuiet(app.pid);  
  51.                        }  
  52.                    }  
  53.                }  
  54.            } else {  
  55.                didOomAdj = false;  
  56.            }  
  57.        }  
  58.        // If we return false, we will fall back on killing processes to   
  59.        // have a fixed limit.  Do this if a limit has been requested; else   
  60.        // only return false if one of the adjustments failed.   
  61.        return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;  
  62.    }<SPAN style="FONT-FAMILY: Calibri; FONT-SIZE: 14px"> </SPAN>  
 final boolean updateOomAdjLocked() {        boolean didOomAdj = true;        final ActivityRecord TOP_ACT = resumedAppLocked();        final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;        if (false) {            RuntimeException e = new RuntimeException();            e.fillInStackTrace();            Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);        }        mAdjSeq++;        // Let's determine how many processes we have running vs.        // how many slots we have for background processes; we may want        // to put multiple processes in a slot of there are enough of        // them.        int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;        int factor = (mLruProcesses.size()-4)/numSlots;        if (factor < 1) factor = 1;        int step = 0;        int numHidden = 0;                // First try updating the OOM adjustment for each of the        // application processes based on their current state.        int i = mLruProcesses.size();        int curHiddenAdj = HIDDEN_APP_MIN_ADJ;  while (i > 0) {            i--;            ProcessRecord app = mLruProcesses.get(i);            //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);            if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {                if (curHiddenAdj < EMPTY_APP_ADJ                    && app.curAdj == curHiddenAdj) {                    step++;                    if (step >= factor) {                        step = 0;                        curHiddenAdj++;                    }                }                if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {                    if (!app.killedBackground) {                        numHidden++;                        if (numHidden > MAX_HIDDEN_APPS) {                            Slog.e(TAG, "No longer want " + app.processName                                    + " (pid " + app.pid + "): hidden #" + numHidden);                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,                                    app.processName, app.setAdj, "too many background");                            app.killedBackground = true;                            Process.killProcessQuiet(app.pid);                        }                    }                }            } else {                didOomAdj = false;            }        }        // If we return false, we will fall back on killing processes to        // have a fixed limit.  Do this if a limit has been requested; else        // only return false if one of the adjustments failed.        return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;    } 
    以上就是android内存管理机制的内容了,在一些设备内存比较低的情况下,我们可以对其内存进行优化,从而让我们的设备运行的更加流畅。


如何防止android app被kill


相较于/data/app下的应用,放在/system/app下的应用享受更多的特权,比如若在其Manifest.xml文件中设置persistent属性为true,则可使其免受out-of-memory killer的影响。如应用程序'Phone'的AndroidManifest.xml文件:
 
   <application android:name="PhoneApp"
                 android:persistent="true"
                 android:label="@string/dialerIconLabel"
                 android:icon="@drawable/ic_launcher_phone">
         ...
    </application>
设置后app提升为系统核心级别,任何情况下不会被kill掉, settings->applications里面也会屏蔽掉stop操作。

这样
设置前的log:   Proc #19: adj=svc  /B 4067b028 255:com.xxx.xxx/10001 (started-services)
    # cat /proc/255/oom_adj
    4
设置后的log:  PERS #19: adj=core /F 406291f0 155:com.xxx.xxx/10001 (fixed)
    # cat /proc/155/oom_adj
     -12                # 这是CORE_SERVER_ADJ
注:init进程的oom_adj为-16(即SYSTEM_ADJ): cat  /proc/1/oom_adj

Android相关部分分析:
在文件frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中有以下的代码:
    final ProcessRecord addAppLocked(ApplicationInfo info) {
        ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);

        if (app == null) {
            app = newProcessRecordLocked(null, info, null);
            mProcessNames.put(info.processName, info.uid, app);
            updateLruProcessLocked(app, true, true);
        }    

        if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
                == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
            app.persistent = true;
            app.maxAdj = CORE_SERVER_ADJ            // 这个常数值为-12。
        }    
        if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
            mPersistentStartingProcesses.add(app);
            startProcessLocked(app, "added application", app.processName);
        }    

        return app;
    }

可见要想成为core service (即app.maxAdj = CORE_SERVER_ADJ(-12)),应用程序需要FLAG_SYSTEM和FLAG_PERSISTENT两个标志,FLAG_SYSTEM指的是应用位于/system/app下,FLAG_PERSISTENT就是指persistent属性。

而对于frameworks/base/services/java/com/android/server/SystemServer.java,则调用
       ActivityManagerService.setSystemProcess();
把自己的 app.maxAdj 设置成SYSTEM_ADJ,即-16。

原理
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。由此带来三个问题:
    1) 回收规则:  什么时候回收与回收哪一个?
    2) 避免误杀:  如何阻止被回收?
    3) 数据恢复与保存:  被回收了怎么办?
 
Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
   1.前台进程( FOREGROUND_APP)
   2.可视进程(VISIBLE_APP )
   3. 次要服务进程(SECONDARY_SERVER )
   4.后台进程 (HIDDEN_APP)
   5.内容供应节点(CONTENT_PROVIDER)
   6.空进程(EMPTY_APP)
 
特征:
1.如果一个进程里面同时包含service和可视的activity,那么这个进程应该归于可视进程,而不是service进程。
2.另外,如果其他进程依赖于它的话,一个进程的等级可以提高。例如,一个A进程里的service被绑定到B进程里的组件上,进程A将总被认为至少和B进程一样重要。
3.系统中的phone服务被划分到前台进程而不是次要服务进程.
 
在android中,进程的oom_adj值也就代表了它的优先级。oom_adj值越高代表该进程优先级越低。文件/init.rc中有以下属性设置:
    setprop ro.FOREGROUND_APP_ADJ       0
    setprop ro.VISIBLE_APP_ADJ                     1
    setprop ro.SECONDARY_SERVER_ADJ   2
    setprop ro.HIDDEN_APP_MIN_ADJ           7
    setprop ro.CONTENT_PROVIDER_ADJ  14
    setprop ro.EMPTY_APP_ADJ                    15
/init.rc中,将PID为1的进程(init进程)的oom_adj设置为SYSTEM_ADJ(-16):
    # Set init its forked children's oom_adj.
    write /proc/1/oom_adj -16

查看本机设置:
cat /sys/module/lowmemorykiller/parameters/adj
0,1,2,7,14,15
 
回收时机:
文件/init.rc中:
   setprop ro.FOREGROUND_APP_MEM       1536      //    6M
   setprop ro.VISIBLE_APP_MEM                     2048     //    8M
   setprop ro.SECONDARY_SERVER_MEM   4096     //  16M
   setprop ro.HIDDEN_APP_MEM                     5120     //  20M
   setprop ro.CONTENT_PROVIDER_MEM    5632     //  22.4M
   setprop ro.EMPTY_APP_MEM                      6144     //  24M
这些数字也就是对应的内存阈值,一旦低于该值,Android便开始按顺序关闭相应等级的进程。
注意这些数字的单位是page: 1 page = 4 kB。所以上面的六个数字对应的就是(MB): 6,8,16,20,22,24。
 
查看现在的内存阈值设置:
cat /sys/module/lowmemorykiller/parameters/minfree

要想重新设置该值(对应不同的需求):
echo   "1536,2048,4096,5120,15360,23040">/sys/module/lowmemorykiller/parameters/minfree
这样当可用内存低于90MB的时候便开始杀死"空进程",而当可用内存低于60MB的时候才开始杀死"内容供应节点"类进程。
 
具体的回收实现在ActivityManagerService.java中的函数trimApplications():
   1.首先移除package已被卸载的无用进程;
   2.基于进程当前状态,更新oom_adj值,然后进行以下操作:
         1) 移除没有activity在运行的进程;
         2) 如果AP已经保存了所有的activity状态,结束这个AP。
   3. 最后,如果目前还是有很多activities 在运行,那么移除那些activity状态已经保存好的activity。
 

更新oom_adj的值:
在ActivityManagerService.java文件的ComputeOomAdjLocked() 中计算出进程的oom_adj,例如:
     if (app == TOP_APP) {
            // The last app on the list is the foreground app.
            adj = FOREGROUND_APP_ADJ;
            app.adjType = "top-activity";
        }
 
Android kernel中的low memory killer
Android的Low Memory Killer根据需要(当系统内存短缺时)杀死进程释放其内存,源代码在kernel/drivers/misc/lowmemorykiller.c中。简单说,就是寻找一个最合适的进程杀死,从而释放它占用的内存。
最合适的进程是:
   •  oom_adj越大
   •  占用物理内存越多
 
一旦一个进程被选中,内核会发送SIGKILL信号将之杀死:
   for_each_process(p) {
        ……
        if(selected == NULL ||   p->oomkilladj > selected->oomkilladj ||
              (p->oomkilladj == selected->oomkilladj && tasksize > selected_tasksize))
        {
             selected = p;
        }
   }
   if(selected != NULL) {
        force_sig(SIGKILL, selected);
   }
 
查看LRU列表:adb shell dumpsys activity
当activitydemo在前台时: 
包含Service的进程的优先级比较高,在computeOomAdjLocked中将其分为了两小类:
      static final int MAX_SERVICE_INACTIVITY = 30*60*1000;                 
      if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
               if (adj > SECONDARY_SERVER_ADJ) {
                            adj = SECONDARY_SERVER_ADJ;
                            app.adjType = "started-services";
                            app.hidden = false;
               }
      }
      if (adj > SECONDARY_SERVER_ADJ) {
                        app.adjType = "started-bg-services";
      }
 

完全让进程不被kill是不可能的,我们可以通过一些操作,使进程被kill的几率变小:
  1) 提高进程的优先级:
        * 后台操作采用运行于前台的Service形式,因为一个运行着service的进程比一个运行着后台activity的等级高;
        * 按back键使得进程中的activity在后台运行而不是destory,需重载back按键(没有任何activity在运行的进程优先被杀).
        * 依赖于其他优先级高的进程;

  2) 强制修改进程属性:
        * 在进程中设置:setPersistent(true);

        * 在Manifest文件中设置(如上)。

本帖最后由 yangjiantong 于 2012-4-28 15:15 编辑

参考链接:http://www.eoeandroid.com/thread-120983-1-1.html
注:本文不代表个人观点,仅是网上搜集的资料,在此做个笔记。

1.在service中重写下面的方法,这个方法有三个返回值, START_STICKY是service被kill掉后自动重写创建
@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }----------------
  @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
                // TODO Auto-generated method stub
                Log.v("TrafficService","startCommand");
                
                flags =  START_STICKY;
                return super.onStartCommand(intent, flags, startId);
//                return  START_REDELIVER_INTENT;
        }
2.在Service的onDestroy()中重启Service.
public void onDestroy() {   
        Intent localIntent = new Intent();
        localIntent.setClass(this, MyService.class);  //销毁时重新启动Service
        this.startService(localIntent);
    }---------------------------------------------
用qq管家杀掉进程的时候,调用的是系统自带的强制kill功能(即settings里的),在kill时,会将应用的整个进程停掉,当然包括service在内,如果在running里将service强制kill掉,显示进程还在。不管是kill整个进程还是只kill掉进应用的 service,都不会重新启动service。不知道你是怎么怎么实现重启的,实在是不解。。。
ps:在eclipse中,用stop按钮kill掉进程的时候,倒是会重启service
KILL问题:
1. settings 中stop service
onDestroy方法中,调用startService进行Service的重启。
2.settings中force stop 应用
捕捉系统进行广播(action为android.intent.action.PACKAGE_RESTARTED)
3. 借助第三方应用kill掉running task
提升service的优先级
--------------------------------------------
service开机启动

http://blog.csdn.net/flying_vip_521/article/details/7053355
  • 今天我们主要来探讨android怎么让一个service开机自动启动功能的实现。Android手机在启动的过程中会触发一个Standard Broadcast Action,名字叫android.intent.action.BOOT_COMPLETED(记得只会触发一次呀),在这里我们可以通过构建一个广播接收者来接收这个这个action.下面我就来简单写以下实现的步骤:  
  •     第一步:首先创建一个广播接收者,重构其抽象方法 onReceive(Context context, Intent intent),在其中启动你想要启动的Service或app。

    • import android.content.BroadcastReceiver;  
    •     import android.content.Context;  
    •     import android.content.Intent;  
    •     import android.util.Log;  
    •       
    •     public class BootBroadcastReceiver extends BroadcastReceiver {  
    •         //重写onReceive方法  
    •         @Override  
    •         public void onReceive(Context context, Intent intent) {  
    •             //后边的XXX.class就是要启动的服务  
    •             Intent service = new Intent(context,XXXclass);  
    •             context.startService(service);  
    •             Log.v("TAG", "开机自动服务自动启动.....");  
    •            //启动应用,参数为需要自动启动的应用的包名
    •     Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);
    •     context.startActivity(intent );        
    •         }  
    •       
    •     }  
  • 第二步:配置xml文件,在receiver接收这种添加intent-filter配置  
  •      <receiver android:name="BootBroadcastReceiver">  
  •                 <intent-filter>  
  •                     <action android:name="android.intent.action.BOOT_COMPLETED"></action>  
  •                     <category android:name="android.intent.category.LAUNCHER" />  
  •                 </intent-filter>  
  •             </receiver>  
  • 第三步:添加权限 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />  

0 0