Android采取了一种有别于Linux的进程管理策略,有别于Linux的在进程活动停止后就结束该进程,Android把这种进程都保留在显存中,直至系统须要更多显存为止。这种保留在显存中的进程一般情况下不会影响整体系统的运行速率,但是当用户再度激活这种进程时,提高了进程的启动速率。
linux系统与android系统不同,linux是一个类unix操作系统,android是一个人们喜爱的常用的操作系统。
一、linux与Windows的显存区别
在Linux中,常常会发觉极少空闲显存,虽然所有的显存都被系统占用了,表面觉得是显存不够用了,实则不然。这是Linux显存管理的一个优秀特点,在这方面,区别于Windows的显存管理。主要特征是,无论数学显存有多大,Linux都将其充分借助,将一些程序调用过的硬碟数据读入显存,借助显存读写的高速特点来提升Linux系统的数据访问性能。而Windows是只在须要显存时,才为应用程序分配显存,并不能充分借助大容量的显存空间。换句话说,每降低一些数学显存,Linux都将能充分借助上去,发挥了硬件投资带来的益处,而Windows只将其作为摆饰,虽然降低8GB甚至更大。
二、android显存的意义
好多人用安卓手机时都不会太在乎剩余显存。Android上的应用是java,其实须要虚拟机,而android上的应用是带有独立虚拟机的,也就是每开一个应用都会打开一个独立的虚拟机。虽然和java的垃圾回收机制类似,系统有一个规则以回收显存。进行显存调度有个阈值,只有高于这个值时,系统就会按一个列表来关掉用户不用的程序。这个值默认设置得很小,所以你会看见显存老在很小的数值徘徊。实际上,它不会影响速率,相反地,推动了上次启动应用的速率。这原本就是android的一个优势,所以,没有太大的必要人为地去关掉进程,非常是使用手动关进程的软件。显存少时,运行小型程序会变慢的缘由是:当显存剩余不多了,打开小型程序时会触发系统自身的调进程调度策略,这些操作非常消耗系统资源,非常是在一个程序频繁向系统申请显存时。这些情况下系统不会关掉所有打开的进程linux系统内存管理,而是选择性关掉,频繁的调度都会拖慢系统。
三、进程管理软件
进程管理软件是很有必要的。运行小型程序之前,你可以人为地关掉一些进程,以释放显存,明显的提升运行速率。但一些小程序完全可交由系统来管理。这么,不关掉程序是不是更耗电?虽然,android的应用被切换到后台时早已暂停了,只保留了运行状态,并不会消耗cpu资源。这就是为何有的程序切出去重进会回到主界面的诱因。但一个程序假如要在后台处理些东西,如音乐播放,它还会开启一个服务。服务可在后台持续运行,所以在后台耗电的只有带服务的应用。你可以通过进程管理软件把带服务的进程关掉。没必要关掉没有带服务的应用,由于它们在后台是完全不耗电的。这些设计原本就十分好的linux基础教程,上次启动程序时会更快,由于不须要读取界面资源,我们又不必要关闭它们,扼杀了android的这个设计优点呢!
四、Android进程种类
1.前台进程(foreground)
目前正在屏幕上显示的进程和一些系统进程。诸如:Dialer,Storage,GoogleSearch等系统进程就是前台进程;再举例来说,当你运行一个程序,如浏览器,当浏览器界面在前台显示时,浏览器属于前台进程(foreground),但一旦你按home回到主界面,浏览器就弄成了后台程序(background)。我们最不希望中止的进程就是前台进程。
2.可见进程(visible)
可见进程是一些不在前台,但用户仍然可见的进程。举个反例:widget、输入法等,都属于visible。这部份进程其实不在前台,但与我们的使用也密切相关,所以也不希望它们被中止(假如时钟、天气,新闻等widget被中止,那它们将难以同步,你也不希望输入法被中止,否则你每次输入时都须要重新启动输入法)。
3.桌面进程(homeapp)
即launcher,保证在多任务切换以后,可以快速返回到home界面,而不需重新加载launcher。
4.次要服务(secondaryserver)
目前正在运行的一些服务(由于主要服务,如拔号等,是不能被进程管理中止的,所以这儿只谈次要服务),举例来说:微软企业套件、Gmail内部储存、联系人内部储存等。这部份服务即使属于次要服务,但和一些系统功能仍然息息相关,须要时常用到,所以也不希望它们被中止。
5.后台进程(hidden)
后台进程(background),也就是一般意义上理解的启动后被切换到后台的进程,如浏览器、阅读器等。当程序显示在屏幕上时,它所运行的进程即为前台进程(foreground),一旦我们按home返回主界面(注意是按home,不是按back),程序就留驻在后台,成为后台进程(background)。
后台进程的管理策略有多种:有较为积极的方法,程序一抵达后台立刻中止,这些方法可以提升程序的运行速率,但未能加速程序的再度启动;也有较悲观的方法,尽可能多地保留后台程序,尽管可能会影响到单个程序的运行速率,但再度启动已启动的程序时,速率会有所提高。这就要根据用户的使用习惯自己找到一个平衡点。
6.内容供应节点(contentprovider)
没有程序实体,提供内容供别的程序去用的,例如月历供应节点、邮件供应节点等。在中止进程时,这类程序应当有较高的优先权。
7.空进程(empty)
空进程,即没有任何东西在内运行的进程。有些程序,例如BTE,程序退出后,仍然会在进程中留驻一个空进程,这个进程里没有任何数据在运行,它的作用常常是提升该程序上次的启动速率或则记录程序的一些历史信息。这部份进程是应当最先中止的。
五、幽灵刽子手LMK(LowMemoryKiller)
1.执行条件
剩余显存大于应用定义的APP_MEM值,开始查看adj值列表,kill相应程序。
2.实现机制
LowMemoryKiller的源代码在kernel/drivers/staging/android/lowmemorykiller.c中
[cpp]view
plaincopy
module_init(lowmem_init);
module_exit(lowmem_exit);
模块加载和退出的函数,主要的功能就是register_shrinker和unregister_shrinker结构体lowmem_shrinker。主要是将函数lowmem_shrink注册到shrinker数组里,在mm_scan调用。
以下详尽地介绍一下这个函数:
[cpp]view
plaincopy
for(i=0;i<a style='color:#0000CC;font-size:16px;' rray_size;i++){
if(other_file<lowmem_minfree[i]){
min_adj=lowmem_adj[i];
break;
other_filelinux培训学校,系统的空闲显存数,按照前面的逻辑判别出,lowmemorykiller须要对adj低于多少(min_adj)的进程进行剖析是否释放。
[cpp]view
plaincopy
if(nr_to_scanmm;
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(tasksizecomm,oom_adj,tasksize);
对每位sig->oom_adj小于min_adj的进程,找到占用显存最大的进程储存在selected中。
[cpp]view
plaincopy
if(selected){
if(fatal_signal_pending(selected)){
pr_warning("process%dissufferingaslowdeath\n",
selected->pid);
read_unlock(&tasklist_lock);
returnrem;
lowmem_print(1,"sendsigkillto%d(%s),adj%d,size%d\n",
selected->pid,selected->comm,
selected_oom_adj,selected_tasksize);
force_sig(SIGKILL,selected);
rem-=selected_tasksize;
发送SIGKILL信息,杀掉该进程。
了解了其机制和原理后,会发觉它的实现特别简单,与标准的LinuxOOM机制类似,只是实现方法略有差异。标准Linux的OOMKiller机制在mm/oom_kill.c中实现,且会被__alloc_pages_may_oom调用(在分配显存时,即mm/page_alloc.c中)。oom_kill.c最主要的一个函数是out_of_memory,它选择一个bad进程Kill,Kill的方式也是通过发送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
plaincopy
#Writevaluemustbeconsistentwiththeaboveproperties.
write/sys/module/lowmemorykiller/parameters/adj0,1,2,7,14,15
write/proc/sys/vm/overcommit_memory1
write/sys/module/lowmemorykiller/parameters/minfree1536,2048,4096,5120,5632,6144
class_startdefault
进程oom_adj同样可以进行设置linux系统内存管理,通过write/proc//oom_adj,在init.rc中,init进程的pid为1,omm_adj被配置为-16,永远不会被杀害。
[plain]view
plaincopy
#Setinititsforkedchildren'soom_adj.
write/proc/1/oom_adj-16
弄清楚了Lowmemorykiller的基本原理,进程omm_adj的大小跟进程的类型以及进程被调度的顺序有关。进程的类型,可以在ActivityManagerService中清楚的看见:
[java]view
plaincopy
staticfinalintEMPTY_APP_ADJ;
staticfinalintHIDDEN_APP_MAX_ADJ;
staticfinalintHIDDEN_APP_MIN_ADJ;
staticfinalintHOME_APP_ADJ;
staticfinalintBACKUP_APP_ADJ;
staticfinalintSECONDARY_SERVER_ADJ;
staticfinalintHEAVY_WEIGHT_APP_ADJ;
staticfinalintPERCEPTIBLE_APP_ADJ;
staticfinalintVISIBLE_APP_ADJ;
staticfinalintFOREGROUND_APP_ADJ;
staticfinalintCORE_SERVER_ADJ=-12;
staticfinalintSYSTEM_ADJ=-16;
ActivityManagerService定义各类进程的oom_adj,CORE_SERVER_ADJ代表一些核心的服务的omm_adj,数值为-12,由上述剖析可知,这类进程永远也不会被杀害。
在init.rc中:
[plain]view
plaincopy
#Definetheoom_adjvaluesfortheclassesofprocessesthatcanbe
#killedbythekernel.TheseareusedinActivityManagerService.
setpropro.FOREGROUND_APP_ADJ0
setpropro.VISIBLE_APP_ADJ1
setpropro.HOME_APP_ADJ1
setpropro.PERCEPTIBLE_APP_ADJ2
setpropro.HEAVY_WEIGHT_APP_ADJ3
setpropro.SECONDARY_SERVER_ADJ4
setpropro.BACKUP_APP_ADJ5
setpropro.HIDDEN_APP_MIN_ADJ7
setpropro.EMPTY_APP_ADJ15
#Definethememorythresholdsatwhichtheaboveprocessclasseswill
#bekilled.Thesenumbersareinpages(4k).
setpropro.FOREGROUND_APP_MEM2048
setpropro.VISIBLE_APP_MEM3072
setpropro.HOME_APP_MEM3072
setpropro.PERCEPTIBLE_APP_MEM4096
setpropro.HEAVY_WEIGHT_APP_MEM4096
setpropro.SECONDARY_SERVER_MEM10240
setpropro.BACKUP_APP_MEM10240
setpropro.HIDDEN_APP_MEM10240
setpropro.EMPTY_APP_MEM14336
#Writevaluemustbeconsistentwiththeaboveproperties.
#Notethatthedriveronlysupports6slots,sowehavecombinedsomeof
#theclassesintothesamememorylevel;theassociatedprocessesofhigher
#classeswillstillbekilledfirst.
write/sys/module/lowmemorykiller/parameters/adj0,1,2,4,7,15
write/proc/sys/vm/overcommit_memory1
write/proc/sys/vm/min_free_order_shift4
write/sys/module/lowmemorykiller/parameters/minfree2048,3072,4096,10240,10240,14336
#Setinititsforkedchildren'soom_adj.
write/proc/1/oom_adj-16
ActivityManagerService.java
打开程序、或有程序步入后台时,就会执行updateOomAdjLocked()函数:
[java]view
plaincopy
finalbooleanupdateOomAdjLocked(){
booleandidOomAdj=true;
finalActivityRecordTOP_ACT=resumedAppLocked();
finalProcessRecordTOP_APP=TOP_ACT!=null?TOP_ACT.app:null;
if(false){
RuntimeExceptione=newRuntimeException();
e.fillInStackTrace();
Slog.i(TAG,"updateOomAdj:top="+TOP_ACT,e);
mAdjSeq++;
//Let'sdeterminehowmanyprocesseswehaverunningvs.
//howmanyslotswehaveforbackgroundprocesses;wemaywant
//toputmultipleprocessesinaslotofthereareenoughof
//them.
intnumSlots=HIDDEN_APP_MAX_ADJ-HIDDEN_APP_MIN_ADJ+1;
intfactor=(mLruProcesses.size()-4)/numSlots;
if(factor<1)factor=1;
intstep=0;
intnumHidden=0;
//FirsttryupdatingtheOOMadjustmentforeachofthe
//applicationprocessesbasedontheircurrentstate.
inti=mLruProcesses.size();
intcurHiddenAdj=HIDDEN_APP_MIN_ADJ;
while(i>0){
i--;
ProcessRecordapp=mLruProcesses.get(i);
//Slog.i(TAG,"OOM"+app+":curhidden="+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,"Nolongerwant"+app.processName
+"(pid"+app.pid+"):hidden#"+numHidden);
EventLog.writeEvent(EventLogTags.AM_KILL,app.pid,
app.processName,app.setAdj,"toomanybackground");
app.killedBackground=true;
Process.killProcessQuiet(app.pid);
}else{
didOomAdj=false;
//Ifwereturnfalse,wewillfallbackonkillingprocessesto
//haveafixedlimit.Dothisifalimithasbeenrequested;else
//onlyreturnfalseifoneoftheadjustmentsfailed.
returnENFORCE_PROCESS_LIMIT||mProcessLimit>0?false:didOomAdj;
进程管理软件正确的用途是杀这些出错的程序、会造成关机有BUG的进程以及疑似病毒进程等,而不是一味地追求显存空得多程序在显存里放着。android显存管理机制就是在一些设备显存比较低的情况下,对其显存进行优化,进而使我们的设备运行更流畅。
了解了android显存的管理机制以后,我们会发觉,只要依照上述文中的资源配置部份进行配置,它的实现似乎很简单。