一、应用程序关闭而不退出
1.关闭-->仅仅是窗口不可见,但其对应的进程还存在
如果后台有许多进程存在的话,只会占用内存空间,而不会降低前台进程的运行速度,为什么?
每个应用程序主体--->ActivityThread,该类初始化后会进入消息循环(Looper.loop)当中
以后则靠消息机制,有消息就处理消息,没有消息就sleep
在queue.next方法中会从消息内部取出消息,如果没有消息则会sleep当前的线程,直到有新消息到来时会唤醒next()方法
queue.next()方法被唤醒的三种情况:
a.定时器中断
操作系统向定时器发送一个任务,该任务会向looper发送一个消息
b.用户按键消息
wms把用户按键消息发送到looper主线程
c.Binder中断
Binder-->Linux的一个驱动
应用程序中可以包含一个binder对象----> Binder驱动接收binder消息派发给客户端binder对象--->binder消息处理中会向looper主线程发送一个消息
2.Android与Linux的配合
Android官方文档指出Activity占用的内存只有在内存不够用的时候才会被回收,而内存是否够用属于Linux内核管理,Ams并不知道
Ams运行在java环境,当java环境内存低时会抛出oom异常,但这并不代表应用程序内存就很低,因为
i.应用程序与Ams运行在两个独立的java虚拟机中,应用程序申请内存并不会通知Ams
ii.java虚拟机运行时都有自己独立的内存空间
综上,单纯的Ams是无法知道系统内存是否低的
什么是系统内存低?
Android中并未采用虚拟内存,故应用程序使用的内存大小取决于物理内存的大小,系统内存低就意味着物理内存所剩无几
Android中运行了一个OOM 进程--->系统启动时会向linux内核注册为一个OOM Killer--->当内存低时linux内核的内存管理模块会通知oom killer---->
oom killer会根据各种规则进行内存释放
Android中的oom killer进程仅适用于Android应用程序,Ams会把每一个应用程序的oom_adj值告诉给oom killer,该值类似于linux的nice值,在-16到15之间,
值越小说明越重要
3.各种关闭程序的过程
i.startActivity开始
startActivity--->暂停当前Activity--->Ams收到Binder消息--->Ams.completePaused--->将activity添加进mStoppingActivities列表
--->目标Activity启动,向Ams发送请求内存回收的消息--->Ams.activityIdleInternal--->调用stopActivityLocked,处理mStoppingActivities中的
activity--->ActivityThread.stop---->Ams.activityStopped--->trimApplications
ii.按back键
finishActivityLocked--->startPausingLocked--->Ams.completePaused--->finish状态为true--->finishingActivityLocked
iii.向Ams发送Idle消息
activityIdleInternal--->trimApplication
iv.释放内存的3个地点
a.在Ams中进行
b.在OOMKiller中进行,Ams告诉oomkiller各个应用进程的优先级,然后oomkiller会调用linux的内核中的内存管理根据优先级杀掉进程
c.应用进程本身之中,通知ActivityThread.scheduleLowMemory和ActivityThread.processInBackground
4.释放内存详解
a.activityIdleInternal被调用的各种原因
i.handleResumeActivity--->addIdleHandler(new Idler())--->Idler.queueIdle--->Ams.activityIdle
ii.HistoryRecord.windowVisible--->发送IDLE_NOW_MSG--->Ams.activityIdle
iii.Ams.completePausedLocked
iv.completeResumeLocked中发生超时--->发送IDLE_TIMEOUT_MSG--->activityInternal
v. activityInternal方法的内部实现
1).通知所有需要回收的客户线程(mProcessesToGc中的进程)进行内存回收
2).取出 mStoppingActivities 列表中的内容,并存放到临时列表stops 中,再取出mFinishigActivities
列表中的内容,并存放到临时列表finishes 中,然后删除原有的记录
3).对stops的activity列表进行处理,改处理过程中为什么要判断finish是否为true?
因为按下“Back”键后,finishing 状态true,接着在completePaused()
中调用到了finishCurrentActivity ( 3 个参数)函数, 该函数中则会把指定的Activity 添加到
mStoppingActivities 列表中,显然,此时该Activity 的finishing 状态为true
stopActivtyLocked通知目标进程ActivityThread调用onStop
4).接着对finish列表中的对象进行处理
ps:以上2、3、4步并没有对客户进程进行主动的内存回收,仅仅是针对不同状态通知
客户进程执行不同的回调而已
5).调用trimApplications,真正意义上的对内存进行回收
vi. trimApplications方法内部执行原理
1).删除mRemovedProcesses中的进程
mRemovedProcesses进程的来源?
1.1 当某个进程crash
1.2 当某个程序的UI 线程在5 秒之内没有响应时,系统会弹出一个ANR 对话框,此时如
果用户选择强制关闭,该进程就会被添加到该列表
1.3 当 程 序 员 调 用 AmS 提供的killBackgroundProcess() 方法时
1.4 当系统启动时,AmS 的systemReady()方法中,如果发现启动了非persistent 类型的应
用进程,则把这些进程添加到列表
2).调用updateOomAdjLocked方法,告诉OOM Killer 指定进程的优先级,若底层的linux系统包含OOMkiller,
则返回true,否则返回false
3).若上一步返回false,则优先杀死后台activity
4).经过以上三步后,若此时的activity数量依然超过阀值,则继续销毁满足一下三个条件的activity:
4.1 activity已经stop了,但是没有finish
4.2 不可见的activity
4.3 不是persistent类型的
vii.updateOomAdjLocked(ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) 告诉OOM 进程指定应用进程的优先级
a).computeOomAdjLocked计算当前进程的adj值
1.估算指定线程的oom_adj值
1.1 如果该进程是TOP_APP
1.2 如果进程中包含instrumentationClass
1.3 如果包含正在执行的receiver对象
1.4 包含正在执行的service对象
以上几步都是最高优先级
1.5 如果包含前台服务对象
1.6 如果进程正在被用户强制调到前台
1.7 如果为home进程
1.8 如果当前activity的数目大于0并且visible
1.9 如果是空进程
综上,以上几步得到的adj值是一个rawAdj,也就是源码中的unlimited,即无限制条件下应有的优先级值
2.对于service和provider的adj值
2.1 如果是备份进程
2.2 处理当前进程中非前台service(即该service不属于前台进程,也没有和前台进程交互)
2.2.1 该app所包含的service的优先级大于前台进程并且所在调度组为背景非交互
2.2.2 该service被请求启动过,并且没超过打击时间(30分钟),优先级设为SECONDARY_SERVER_ADJ
2.2.3 处理和该service连接的客户端,并根据其客户端的优先级调整其service的优先级,如果客户端是该进程本身,不作处理
2.2.4 如果是BIND_AUTO_CREATE方式创建的service
2.2.5 判断客户连接对应的activity
2.3. 处理provider的情况(与service基本相同)
2.4 查看上述的adj值是否超过系统给定的对大值
b) 1.判断当前app是否需要从前台切换到后台
2. 真正的adj值已改变
3. 所在调度组发生变化
viii.判断当前app的curAdj值
viv.Ams内部内存回收潜规则(oom killer)
vv.scheduleAppGcLocked通知指定的app对象进行内存回收
performAppGcsIfAppropriateLocked :处理GC_BACKGROUND_PROCESSES_MSG消息
canGcNowLocked:判断是否适合进行回收
即:
.当前没有正在执行的Broadcastreceiver
.当前处于sleep状态或者正在执行的activity处于idle状态
performAppGcsLocked
performAppGcLocked
ps:当客户进程启动失败是会将app.reportLowMemory设置为true
ActivityThread.scheduleLowMemory
ActivityThread.handleLowMemory处理上面的方法
processInBackground方法
ps: processInBackground方法只会回收Binder相关的内存
5.如何理解activity
a. Activity并不对应一个应用程序,ActivityThread才对应一个应用程序
b. 默认activity会添加一个窗口,但实际上可以修改,使其不添加任何窗口
c. 在系统内存低的时候会释放调显存