优化后台推送的service,减少被杀死的几率
做之前大概思路是:基本参考的原理是官方对内存清理时的5个优先级别,制造出一个单独的接收push的进程来放push service。涉及到的问题包括官方的说明、service启动相关原理,一个app两个进程的知识,两个进程间的通信。
---------------------mark:T9200,HM1S的代码:NotifyService每5秒发parseReceiver的通知。网络变化主动stop ParseService。C8825增加了解锁时启动NotifyService。
参考1:微信的两个进程:http://www.cnblogs.com/GIS-Dream/p/3246534.html
参考2:android进程间通信:http://blog.csdn.net/victory08/article/details/8696252
参考3:Application有一个override方法叫onLowMemory
参考4:官方:http://developer.android.com/guide/components/processes-and-threads.html
参考5:service 的通信有三种方式:Extending the Binder class;Using a Messenger;Using AIDL
Extending the Binder class This is the preferred technique when your service is merely a background worker for your own application. The only reason you would not create your interface this way is because your service is used by other applications or across separate processes.
参考6:parse是依赖于gcm的。从manifest可以看出来。国行手机阉割掉的主要是这四个:【1】GoogleServicesFramework.apk(此为必需!要用google服务就得装!)
【2】GoogleContactsSyncAdapter.apk和【3】GoogleCalendarSyncAdapter.apk可根据自己需要安装,不用联系人和日历同步则可以不装,【4】Google Play .APK如果 你想用上google商店----------------这4个APK合起来就是google的服务框架,安装完这几个APK就可以兼容谷歌基本所有的应用。
GCM的问题:“先不提4.0之前必须登录google账户才能用,gcm容易经常被墙,容易被rom删掉。到达率50%还是80%还是90%又如何?不是100%就没法用。即使100% 的android手机都有,偶尔墙一下也受不了。
参考7:手机360卫士的一些牛B权限:
安全类:1,修改系统设置;2,在其他应用之上进行绘图;3,对正在运行的应用重新排序(移动到前台或者后台reorder other app);4,直接安装应用;5,重新设置外拨电话的路径;
隐私类:1,检索正在运行的应用;
其它类:1,修改安全系统设置;2,关闭其他应用 ;3,删除所有应用缓存数据;4,强制关闭后台应用;5,查阅敏感日志数据;
手机360卫士需要有root权限才能做的是:自启动软件管理,软件权限监控等。所有的权限都定义在android.Manifest类中。ActivityManager类有moveTaskToFront, killBackckProcess,getRunningAppProcess等功能。
参考8:
官网:
A started service can use the startForeground(int, Notification)
API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory. (It is still theoretically possible for the service to be killed under extreme memory pressure from the current foreground application, but in practice this should not be a concern.)
参考9:stack网上一篇讨论:http://stackoverflow.com/questions/7142921/usage-of-androidprocess
首先,关于manifest中的一些细节还需要挖掘一下。http://developer.android.com/guide/topics/manifest/manifest-element.html#uid
然后,官网的Training模块关于多Process的讨论。http://developer.android.com/training/articles/memory.html#MultipleProcesses
还有,官网的Tools模块关于Investigate RAM的介绍
参考10:出现了新的问题,当定义了新的process,新的process会Replicate很多原process的内存过来,导致一个空的service也要15M的内存。而原process内存未减少。
一方面尝试主动去控制新process中的内容,另一方面尝试主动控制activity资源的在后台时的释放。
参考11:把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity占有的资源:view hierachy, resource等。
避免这种内存泄露的方法是避免activity中的任何对象的生命周期长过activity,避免由于对象对 activity的引用导致activity不能正常被销毁。我们可以使用application context。application context伴随application的一生,与activity的生命周期无关。application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取。
避免context相关的内存泄露,记住以下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context
3. 避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化
【其他的相关事项】
1)在SDK中的DigitalClock Widget ,因为DigitalClock要注册一个observer,所以会用把载上DigitalClock widget的Activity作为那个observer。但在SDK的DigitalClock是有一个Bug的,因为在DigitalClock 的onDetachedFromWindow中是没有unregister 那个observer的。 解决方法是自己写一个DigitalClock。详情请看附上的代码(DigitalClockNew.java)。
2)在SDK中的Toast的function makeText 是要求传一个Context的,但在Toast的代码中,这个Context是会用做callback上。如果是传Activity作为那个 Context的话,那会发生memory leak的问题。解决方法是传 Application Context,而不是ActivityContext。
【如何查看Memory leak的问题】
如果怀疑有memory leak的问题,可先执行那个apk在emulator上,然后在PC上执行adb shell,,然后执行ps,查看你的process 的pid。
在apk上执行有memory leak可疑的动作后,可以做下面的诊断
1. 执行 dumpsys meminfo <pid>
这个指令显示pid的memory资料。注意是 Activity的 数量,如果数量是不断上升,那就是有memory leak。 注意,因为在未执行Gargage Collect前,Activity是不会被释放的。可以在DDMS上执行手动的Gargage Collect。
2. 把process 的memory dump 出来,看memory leak的所在
先执行 chmod 777 /data/misc,然后执行 kill -10 <pid> ,在 /data/misc 上会看到那个pid 的memory leak,(如heap-dump-tm1265266619-pid1673.hprof )
用adb pull ( 如adb pull /data/misc/ heap-dump-tm1265266619-pid1673.hprof 1673.hprof )把这个档案拷回电脑上。
然后,用在PC上执行hprof-conv (如hprof-conv 1673.hprof 1673_a.hprof) 把那个拷回来的hprof转换成 Eclipse Memory Tool 可以支持的格式。
用Eclipse Memory Tool (http://www.eclipse.org/mat/), 打开转换了的memory dump。 在Eclipse Memory Tool 上,按OQL,输入 “select * from instanceof android.app.Activity” , 这个指令可以找所以在系统上是android.app.Activity 的 instance。(详见下图)
如果在object的旁带有“Unknown”的话,那object是可以被Gargage Collect的。要看其他的object是什么原因不可以被Gargage Collect 的话,可以在那个object上right-click,然后选Path to GC Roots, exclude weak/soft reference 。 (weak 和soft reference 都是可以被VM查到的,所以是可以Gargage Collect的。)
在Path to GC Roots 中,可以看到WidgetManagerHome 是因为Toast中的inner class TN 把 这个WidgetManagerHome抓住了。
(关于查找leaks,参考下这个http://blog.crowdint.com/2013/10/02/fixing-memory-leaks-in-android-applications.html)
==============================================================================
记录:
经过多日的研究,这里简单记录一下。
1,结束service时,不会结束进程。service被杀掉的话,process其实还在。所以可以不必让service的onDestroy中自动重启。
2,内存紧张时进程被杀掉后,如果service有自动重启,那么整个进程都会执行一次新的启动过程。
2.5,而service没有自动启动的话,内存紧张杀进程还,还是重启了进程,是不是代码其他地方有处理---此现象只在红米上设置允许自动重启的时候会出现。
3,service被结束后,其Thread变量还在运行,why?
4,onTrimMemory调用可能会很频繁,不可做过多处理
5,没有activity有Service的进程更安全。但是:xxx增加一个进程,会复制很多context环境进去,有可能占用更大的内存
6,叮咚在内存多次告急(80分)时,还不释放activity,应该是有内存泄露,无法回收。
7,叮咚的MainDingtone有泄露,即使主动调用了finish()方法,还是无法释放activity的资源
现在要解决的问题是:1,could not construct writer是不是有切换网络的原因?2,如何主动的把activity资源释放掉?3,尝试监听网络状态,主动关掉parseService,让其自动重启。
注:
已优化:
按键音播放;
其他待优化:
UI缓存跳转的优化;数据模型的抽象共用优化;Activity,View等抽象共用优化;