当一个应用的组件开始运行,并且这个应用没有其它的组件在运行,系统会为这个应用启动一个新的Linux进程,这个进程只有一个线程.默认情况下,一个应用的所有组件都运行在一个进程和线程(主线程)中.如果一个应用的组件开始运行,并且已经存在这个应用的线程了(因为这个应用的另一个组件已经运行了),于是这个组件就会在这个已有的进程中启动并且运行在同一线程中.然而,你完全可以安排不同的组件运行于不同的进程,并且你可以为任何程序创建另外的线程.
进程
默认下,同一个应用的所有组件都运行在同一个进程中并且大多数程序不必改变这一状况.然而,如果你非要与众不同,也可以通过修改manifest文件实现.manifest文件中的所有支持android:process属性的那些项(<activity>,<service>, <receiver>, 和<provider>)都可以指定一个进程,于是这些组件就会在这个进程中运行.你可以设置这个属性使每个组件运行于其自己的进程或只是其中一些组件共享一个进程.你也可以设置android:process以使不同应用的组件们可以运行于同一个进程—假如这些应用共享同一个用户ID并且有相同的数字证书.
<application>元素也支持android:process属性,用于为所有的组件指定一个默认值.
Android可能在某些时刻决定关闭一个进程,比如内存很少了并且另一个进程更迫切的需要启动时.进程被关闭时,其中的组件们都被销毁.如果重新需要这些组件工作时,进程又会被创建出来.
当决定关闭哪些进程时,Android系统会衡量各进程与用户的紧密程度.例如,比起一个具有可见的activity的进程,那些所含有的activity是全部不可见的进程更容易被关闭.如何决定一个进程是否被关闭,取决于进程中运行的组件们的状态.决定关闭进程的规则将在下面讨论.
进程的生命期
Android系统会尽量维持一个进程的生命,直到最终需要为新的更重要的进程腾出内存空间。为了决定哪个该杀哪个该留,系统会跟据运行于进程内的组件的和组件的状态把进程置于不同的重要性等级。当需要系统资源时,重要性等级越低的先被淘汰。
重要性等级被分为5个档。下面列出了不同类型的进程的重要性等级(第一个进程类型是最重要的,也是最后才会被杀的):
1前台进程
用户当前正在做的事情需要这个进程。如果满足下面的条件,一个进程就被认为是前台进程:
这个进程拥有一个正在与用户交互的Activity(这个Activity的onResume()方法被调用)。
这个进程拥有一个绑定到正在与用户交互的activity上的Service。
这个进程拥有一个前台运行的Service — service调用了方法startForeground().
这个进程拥有一个正在执行其任何一个生命周期回调方法(onCreate(),onStart(),或onDestroy())的Service。
这个进程拥有正在执行其onReceive()方法的BroadcastReceiver。
通常,在任何时间点,只有很少的前台进程存在。它们只有在达到无法调合的矛盾时才会被杀--如内存太小而不能继续运行时。通常,到了这时,设备就达到了一个内存分页调度状态,所以需要杀一些前台进程来保证用户界面的反应。
2可见进程
一个进程不拥有运行于前台的组件,但是依然能影响用户所见。满足下列条件时,进程即为可见:
这个进程拥有一个不在前台但仍可见的Activity(它的onPause()方法被调用)。当一个前台activity启动一个对话框时,就出了这种情况。
3服务进程
一个可见进程被认为是极其重要的。并且,除非只有杀掉它才可以保证所有前台进程的运行,否则是不能动它的。
这个进程拥有一个绑定到可见activity的Service。
一个进程不在上述两种之内,但它运行着一个被startService()所启动的service。
尽管一个服务进程不直接影响用户所见,但是它们通常做一些用户关心的事情(比如播放音乐或下载数据),所以系统不到前台进程和可见进程活不下去时不会杀它。
4后台进程
一个进程拥有一个当前不可见的activity(activity的onStop()方法被调用)。
这样的进程们不会直接影响到用户体验,所以系统可以在任意时刻杀了它们从而为前台、可见、以及服务进程们提供存储空间。通常有很多后台进程在运行。它们被保存在一个LRU(最近最少使用)列表中来确保拥有最近刚被看到的activity的进程最后被杀。如果一个activity正确的实现了它的生命周期方法,并保存了它的当前状态,那么杀死它的进程将不会对用户的可视化体验造成影响。因为当用户返回到这个activity时,这个activity会恢复它所有的可见状态。
5空进程
一个进程不拥有入何active组件。保留这类进程的唯一理由是高速缓存,这样可以提高下一次一个组件要运行它时的启动速度。系统经常为了平衡在进程高速缓存和底层的内核高速缓存之间的整体系统资源而杀死它们。跟据进程中当前活动的组件的重要性,Android会把进程按排在其可能的最高级别。例如,如果一个进程拥有一个service和一个可见的activity,进程会被定为可见进程,而不是服务进程。另外,如果被其它进程所依赖,一个进程的级别可能会被提高—一个服务于其它进程的进程,其级别不可能比被服务进程低。因为拥有service的进程比拥有后台activitie的进程级别高,所以当一个activity启动一个需长时间执行的操作时,最好是启动一个服务,而不是简单的创建一个工作线程。尤其是当这个操作可能比activity的生命还要长时。例如,一个向网站上传图片的activity,应该启动一个service,从而使上传操作可以在用户离开这个activity时继续在后台执行。使用一个service保证了这个操作至少是在"服务进程"级别,而不用管activity是否发生了什么不幸。这同样是广播接收者应该使用service而不是简单地使用一个线程的理由。
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服务被划分到前台进程而不是次要服务
进程.
android4.0的processlist.java中
static final int HIDDEN_APP_MAX_ADJ = 15;
static int HIDDEN_APP_MIN_ADJ = 9;
static final int SERVICE_B_ADJ = 8;
static final int PREVIOUS_APP_ADJ = 7;
static final int HOME_APP_ADJ = 6;
static final int SERVICE_ADJ = 5;
static final int BACKUP_APP_ADJ = 4;
static final int HEAVY_WEIGHT_APP_ADJ = 3;
static final int PERCEPTIBLE_APP_ADJ = 2;
static final int VISIBLE_APP_ADJ = 1;
static final int FOREGROUND_APP_ADJ = 0;
static final int PERSISTENT_PROC_ADJ = -12;
static final int SYSTEM_ADJ = -16;
static final int MIN_HIDDEN_APPS = 2;
static final int MAX_HIDDEN_APPS = 15;
在android中以进程的oom_adj值也就代表了它的优先级.
oom_adj值越高代表该进程优先级越低. Init.rc中:
回收时机:
private final int[] mOomAdj = new int[] {
FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, HIDDEN_APP_MAX_ADJ
};
// HVGA or smaller phone with less than 512MB. Values are in KB.
private final long[] mOomMinFreeLow = new long[] {
8192, 12288, 16384,
24576, 28672, 32768
};
// These are the high-end OOM level limits. This is appropriate for a
// 1280x800 or larger screen with around 1GB RAM. Values are in KB.
private final long[] mOomMinFreeHigh = new long[] {
32768, 40960, 49152,
57344, 65536, 81920
};
通过计算最大和最小值,得出8084,10114,12144,14192,16222,20264
对应的mOomAdj里成员的内存阈值,一旦低于该值,Android
便开始按顺序关闭相应的进程 .
同时把计算结果保存在
cat /sys/module/lowmemorykiller/parameters/minfree
具体的回收实现在ActivityManagerService.java中的函
数trimApplications()
1.首先移除package被移走的无用进程.
2.基于进程当前状态,更新oom_adj值,然后进行以下操作.
l移除没有activity在运行的进程
l如果AP已经保存了所有的activity状态,结束这个AP.
3.最后,如果目前还是有很多activities 在运行,那么移除那些activity状态已经保存好的activity.
更新oom_adj的值
Android kernel中的low memory killer
Android的Low Memory Killer根据需要(当系统内存短
缺时)杀死进程释放其内存,源代码在
kernel/drivers/misc/lowmemorykiller.c
简单说就是寻找一个最合适的进程杀死,从而释放
它占用的内存.
最合适:
•oom_adj越大
•占用物理内存越多
一旦一个进程被选中,内核会发送SIGKILL信号将之杀死.
for_each_process(p) {
……
service
iis7站长之家(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.提高进程的优先级:
l后台操作采用Service形式,因为一个运行着service的进程比一个运行着后台activity的等级高。
l按back键使得进程中的activity在后台运行而不是destory,需重载back按键(没有任何activity在运行的进程优先被杀).
l依赖于其他优先级高的进程.
强制修改进程属性:
•在程序中设置setPersistent(true);
•在project的androidmanifest.xml的
中加入属性android:persistent="true"
android:persistent(SDK)
Whether or not the application should remain running at all times . The default value is "false". Applications should not normally set this flag; persistence mode is intended only for certain system applications(phone,system).
1.使用killProcess (int pid)可以杀死指定PID的进程
public void onClick(View v) {
android.os.Process.killProcess(android.os.Process.myPid());
}
使用system.exit(0);可以达到同样的效果.
2.使用finish()可以杀死当前的activity
1. 保存资料:最好在每次Activity 运行到onPause或
onStop状态时先保存资料,然后在onCreate时将资
料读出来(生命周期方法).
2. OnSaveInstanceState(非生命周期方法)
onRestoreInstanceState