android 进程保活

转载自:
https://blog.csdn.net/xiaoxiaohu_/article/details/73639637
http://www.infoq.com/cn/articles/wechat-android-background-keep-alive
https://www.jianshu.com/p/63aafe3c12af
在安卓系统中,进程被杀的原因通常分为几个方面:
1、应用crash
2、系统回收内存
3、用户触发
4、第三方root权限app

这里讨论的是第2项,如何应对android Lowmemory killer。

熟悉安卓系统的人都知道,系统处于体验和性能的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将这个进程缓存起来,打开的应用越多,后台缓存的进程也就越多,在系统内存不足的情况下,系统开始依据自身的一套进程回收机制来判断要kill掉哪些进程,以腾出内存来供给需要的app。这套回收内存的机制叫做Low memory killer。他是基于Linux内核OOM killer(out of memory killer)机制诞生。

了解完Low Memory killer,再说一下oom_adj。他是linux内核分配给每个系统进程的一个值,代表进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收。oom_adj的作用有以下几点:

  • 进程的oom_adj越大,表示此进程的优先级越低,越容易被杀回收;越小,表示进程优先级越高,越不容易被杀回收
  • 普通app进程的oom_adj>=0,系统进程的oom_adj才可能小于0.

可以用到下面两个命令来查看进程的oom_adj值,

ps | grep PackageName //获取制定进程的信息

这里写图片描述
红色圈中是下面三个进程的id
UI进程:com.clock.daemon
普通后台进程:com.clock.daemon:bg
灰色保活进程:com.clock.daemon:gray
这些也可以在android studio中获得:
这里写图片描述

接下来获取三个进程的oom_adj

cat /proc/进程ID/oom_adj

这里写图片描述
从上图可以看出,UI进程和灰色保活service进程的oom_adj=0,而普通后台进程oom_adj =15 到这里你估计也能明白,为什么普通的后台进程容易被回收,而前台进程不容易被回收。
看看下面的图:
这里写图片描述
我把app切换到后台,再进行oom_adj的实验,你会发现UI进程的值从0变成6,灰色保活的service进程从0变成1,这里可以观察到,app退到后台时,其所有的进程优先级都会降低,但是UI进程是降低非常明显的,因为他占用资源最多,系统内存不足的时候肯定优先杀这些占用内存高的进程来腾出资源,所以,为了尽量避免后台UI进程被杀,需要极可能的释放一写不用的资源,尤其是图片,音频之类的。

android中进程种类

系统强制销毁进程时,面临一个问题:系统当中可能会运行多个进程,销毁哪些合适呢?这就是我们要讨论的进程优先级问题。进程被系统强制销毁时,是按照进程的优先级进行的。而进程的优先级主要和应用包含的组件相关。进程优先级从高到底可分为四种:前台进程、可视进程、服务进程、缓存进程

  • 前台进程

需要用户当前正在进行的操作。一般满足一下条件:
1、屏幕顶层运行Activity,用户正与之交互。
2、有BroadcastReceiver正在执行代码
3、有Service在其回调方法(onCreate(),onStart(),onDestroy())中正在执行代码。
这种进程较少,一般来作为最后的手段来回收内存。

  • 可视进程

做用户当前意识到的工作,一般满足以下条件:
1、屏幕上显示Activity,但不可操作(处于onPause()状态),比如说该activity上面有个透明的activity,或者有个dialog。
2、有service通过调用Service.startForeground()作为一个前台服务运行
3、含有用户意识的特定的服务,如动态壁纸、输入法等。
这些进程很重要,一般不会杀死,除非这样做可以使得所有前台进程存活。

服务进程:含有以startService()方法启动的service。虽然该进程用户不直接可见,但是他们一般做一些用户关注的事情(如数据的上传下载)
这些进程一般不会杀死,除非系统内存不足以保持前台进程和可是进程的运行。

对于长时间运行的service(如30分钟以上),系统会考虑将之降级为缓存进程,避免长时间运行导致内存泄露或其他问题,占用过多RAM以至于系统无法分配充足资源给缓存进程。

  • 缓存/后台进程

包含多个activity实例,但是都不可见(处于onStop且已返回)
系统如有内存需要,可随意杀死。
下面分享几种微信保活的方法:

进程拆分

很多人在实际开发中,基本都不会去给app划分进程,而且,在android中使用多进程,还可能需要编写额外的进程通信代码,可能带来额外的bug,无疑加大了开放的工作量。

整个app在一个进程有什么弊端

在android中,虚拟机飞赔给各个进程的运行内存是有限制的(可能是32M,48M,64M,根据机型而定)如果在app中,增加了一个很常用的图片选择模块用于上传图片或者头像,加载大量bigmap会使app的内存占用迅速增加,如果你还把查看过的图片缓存在了内存中,那么OOM的风险将会大大增加,如果此时还需要使用Webview加载一波网页,那这就很危险了。
微信开发团队在《android内存优化杂谈》一文中就说到:“对于Webview,图库等,由于存在内存系统泄露或者占用内存过多的问题,我们可以采用单独的进程,微信当前也会把它们放在单独的tool进程中。”
这里写图片描述
上图表示的是微信主要的几个进程:
1、push主要用于网络交互,没有UI
2、worker就是用户看到的主要UI
3、tools主要包含gallery和webview
拆分网络进程,确实是为了减少进程回收带来的网络断开
这里写图片描述
可以看到push的内存要远远小于worker,而且push的工作性质稳定,内存增长非常少,这样就可以保证,尽量减少push被杀的可能性。
这里有个思路,但是限制比较多,启动一个纯c/c++进程,没有java run time,内存使用极低。
这种做法限制很明显,如没有java run time,所以无法使用android系统接口,缺乏权限,也无法使用分钟shell命令操作(如am)但可以考虑一下用途:高强度运算,网络连接,心跳维持等。比如shadowsocks-android就如此,使用纯c命令行进程,维护和socks5的代理

tools进程的拆分同样也是内存原因:
1、老版本的webview是有内存泄露的
2、Gallery大量缩略图导致内存使用大
微信在进入后台后,会主动把tools进程kill掉。

及时拉起

系统回收不可避免,即使重新拉起的手段主要依赖系统特性,从上图可以看到,push有AlarmReceiver ConnectReceiver BootReceiver。这些receiver都可以在push被杀后,重新拉起。特别AlarmReceiver,结合心跳逻辑,微信被杀后,重新拉起最多一个心跳周期。
而对于worker,除了用户UI操作启动。在接收消息,或者网络切换等事件,push也会通过LocalBroadcast,重新拉起worker。这种拉起worker,大部分初始化已经完成,也能大大提高用户点击微信的启动速度。

进程优先级

Low Memory Killer决定是否杀进程除了内存的大小,还有进程优先级。提高进程优先级是保活的最好手段
原理:android的前台service机制。但该机制的缺陷是通知栏保留了图标。
对于 API level<18,调用startForeGround(ID,new Norification())发送空的Notification,图标则不会显示。
对于API level >=18,在需要提高优先级的service A启动一个InnerService,两个服务同时startForeground,且绑定同样的ID。stop掉InnerService,这样通知栏的图标即被移除。
这种方案其实是利用的android 前台service的漏洞。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值