上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值
上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值
当我们应用在前台的时候,无论adj还是score还是score_adj,他们的值都非常的小,基本不会被LMK所杀掉,但是当我们按了Home之后,进程的adj就会急剧增大,变为7,相应的score和score_adj也会增大。在上篇文章中我们得知,adj=7即为被切换的进程,两个进程来回切换,上一个进程就会被设为7。当我们按Back键的时候,adj就会被设为9,也就是缓存进程,优先级比较低,有很大的几率被杀掉。
接着我们分析B
B是直接启动一个后台service并且播放音乐,这个处理看起来比A好了很多,那么实际上,B的各个场景的优先级和A又有什么不同呢?让我们来看下B的对应的打开、切换、退出相应的adj、score、score_adj的值。(下面三张图依次对应为【打开状态】、【按了Home键被切换状态】、【按了Back键被退出状态】)
上图为打开状态下oom_adj、oom_score、oom_score_adj的值
上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值
上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值
B的情况其实是与A类似的,三种状态的adj、score_adj的值都是一样的,只有score有一点出入,其实分析源码得知,LMK杀进程的时候,score的左右其实并不大,所以我们暂时忽略它。所以,与A相比,他们的adj和score_adj的值都相同,如果遇到内存不足的情况下,这两个应用谁占得内存更大,谁就会被杀掉。不过鉴于A实在activity中播放音乐,所以B还是比A略好的方案。
这里有朋友肯定要问了,为什么切到后台后,adj的值是7而不是5,后台不是还有service在跑吗?
我们通过查看源码可以找出来,当切换Home的时候,会调用ActivityStack.java
的finishCurrentActivityLocked
函数,然后调用到了ActivityManagerService.java
的computeOomAdjLocked
函数,在这里,对进程的ADJ值进行重新计算。
if (app == mPreviousProcess && app.activities.size() > 0) {
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.cached = false;
app.adjType = “previous”;
}
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
}
}
当进程为PreviousProcess情况,则ADJ=7。
具体的计算流程请看这里computeOomAdjLocked计算流程
接下来分析C
C的话是启动一个前台Service来播放音乐。让我们来看一下对应的值。(下面三张图依次对应为【打开状态】、【按了Home键被切换状态】、【按了Back键被退出状态】)
上图为打开状态下oom_adj、oom_score、oom_score_adj的值
上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值
上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值
在前台的时候,和AB是一样的,adj都是0,当切到后台,或者back结束时,C对应的adj就是2,也就是可感知进程。adj=2可以说是很高优先级了,非root手机,非系统应用已经没有办法将其杀掉了。具体可参见ActivityManagerService的killBackgroundProcesses
方法以及killPackageProcessesLocked
方法。adj<5的应用不会被杀掉。
总的来说,C方案比B优秀,拥有前台Service的C更不容易被系统或者其他应用所杀掉了,进程的优先级一下子提高到了2,相对于B来说更稳定,用户体验更好。不过有一点不足是必须启动一个前台service。不过现在大部分的音乐类软件都会提供一个前台service,也就不是什么缺点了。其实也是有灰色方法可以启动一个不显示通知的前台service,这里就不过多介绍了。
那么还有可改进的余地吗?
答案当然是肯定的。
让我们来看看D ,终于我们的主角,多进程登场了。
D把应用进行了拆分,把用于播放音乐的service放到了新的进程内,让我们看一下对应的值。(下面三张图依次对应为【打开状态】、【按了Home键被切换状态】、【按了Back键被退出状态】)
上图为打开状态下oom_adj、oom_score、oom_score_adj的值
上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值
上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值
上面三张图对应的是D应用主进程的ADJ相关值,我们可以看出来,跟A类似,adj都是0,7,9。由于少了service部分,内存使用变少,最后计算出的oom_score_adj也更低了,意味着主进程部分也更不容易被杀死。
下面我们看下拆分出的service的相关值
上图为后台Service的oom_adj、oom_score、oom_score_adj的值
因为是service进程,所以不受打开,关闭,切换所影响,这里就放了一张图。
我们可以看到,service的adj值一直是5,也就是活跃的服务进程,相比于B来说,优先级高了不少。不过对于C来说,其实这个方案反倒不如C的adj=2的前台进程更稳定。但是D可以自主释放主进程,使D实际所占用的内存很小,从而不容易被杀掉。那么到底C和D谁是更优秀的设计?我个人认为,在ABCDE这5个设计中,D是最具智慧的设计,具体是为什么?先卖个关子,等我们说完了E,再作总结。
那就赶紧分析E吧
E也是使用了多进程,并且在新进程中,使用了前台service,先来看下对应的值。(下面三张图依次对应为【打开状态】、【按了Home键被切换状态】、【按了Back键被退出状态】)
上图为打开状态下oom_adj、oom_score、oom_score_adj的值
上图为按了Home键状态下oom_adj、oom_score、oom_score_adj的值
上图为按了Back键状态下oom_adj、oom_score、oom_score_adj的值
这个不多解释,和ABD基本差不多,都是0,7,9。我们看下拆分出来的进程的值。
上图为后台Service的oom_adj、oom_score、oom_score_adj的值
我们可以看到,这个进程的值是2,像C方案,非常小,非常稳定,而且,我们还可以在系统进入后台后,手动杀掉主进程,使整个应用的内存消耗降到最低,内存低,优先级又高,E获得了今天的最稳定的方案奖。
小结
ABCDE,5种方案都已经分析完了。显然,E是最稳定的方案,不过,我刚才说过,我个人最倾向于D方案,并且认为D是最智慧的方案,这是为什么呢?
其实我们可以做个比喻,把整个Android系统比喻成一个旅游景点,Low Memory Killer就是景点的门卫兼保安,然后我们每个进程的ADJ相当于手里的门票,有的人是VIP门票,有的人是普通门票。景点平常没人的时候还好,谁拿票都能进,当人逐渐拥挤的时候,保安就开始根据票的等级,往外轰人。E方案就是一个拿着普通票的妈妈,带着一个VIP的孩子去参观,D方案就是一个拿着普通票的妈妈,带着一个拿着中等票的孩子参观。当内存不够的时候,保安会先把两个妈妈轰出去,孩子们在里面看,再不够了,就会把D孩子给轰出去。这么看来,显然E的效果更好一些,不过由于Android系统对于VIP票的发放没有节制,大家都可以领VIP票,那也就是相当于没有VIP票了。所以如果E方案是一种精明,那么D才是真正的智慧。将调度权还给系统,做好自己,维护好整个Android生态。
其实现阶段,如果公司要做一个后台类型的应用,我个人也是会选择追逐眼前里利益,采用E方案的,这也是不得已而为之,大家都利用漏洞拿VIP票,你不拿,将来做出来的APP出了偏差,你是要负责任的,所以还是希望Android能把漏洞堵住,把内存分配给真正需要的人,而我们自己也应该遵守规矩,维护整个生态平衡。
还有一点,是因为现在部分Root的手机都有优化大师,其实这个优化大师,就好比是个临时工门卫,告诉你他能解决景区爆满问题,实际上他的做法是,把一些票的等级降低,比如把中等票变成赠票,然后给你名正言顺的轰出去,听着是不是很耳熟?“让一部分人先富裕起来,然后把不富裕的杀掉,达成共同富裕。”
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
分享一份NDK基础开发资料
分享内容包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
…(img-WWHpEWHs-1712350070093)]
分享内容包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!