Android开发-细节决定性能

最近换了个新的团队,刚刚入职的一段时间没有分配太多的工作,主要是熟悉代码和其他一些流程,在开需求评审会议的时候说到了性能优化的问题,但是这个由于开发任务的影响并没有安排人去做,那么我就自己默默的利用MAT和DDMS去对产品进行了性能分析,具体分析的过程和方法我就不想在这里花很多时间介绍了,主要总结一下出现问题是对我们平时编程的启示。

内存泄漏

一、单例对象的滥用

关于单例造成的内存泄漏,网上说的太多了。主要原因大部分都是Activity对象被单例类持有、Handler持有等,其实我在项目中发现的就是单例持有,但是比较隐蔽,我来说一下发现泄漏的地方,以及对我们开发的启示。泄漏发生的示意图如下:

Android开发-细节决定性能_第1张图片
对象创建依赖

这里可以很直接的看到在创建A对象时将Activity作为参数传递到A中使用,但是在A中又创建了B对象,并且B的构造函数包含Context,这个时候很自然的用了A中的Activity作为参数创建了B对象,但是这个时候麻烦来了,在B中创建了C对象并且改类是单例类,这个时候这个单例类就持有了Activity,那么这个时候如果退出改Activity就有可能存在泄漏。这里就以上这个发现的代码我想总结一下我们平时开发时需要注意的细节:
1.在创建类的时候不要轻易的将Activity作为构造函数的参数
 通过上面的问题我们可以发现,当你把Activity作为某个类的参数传递进去的时候,在该类中对Activity的使用有可能会失去控制(如上面所示)。如果非要使用Activity作为参数或者代码中已经这样了,可以尝试着在该类中创建两个成员变量:mActivity和mContext,这里的mContext可以通过Application的Context。
2.在使用单例类时,获取对象的方法尽量不要含有参数
 如上泄漏问题,如果类C的getInstance方法不需要Context作为参数,那么就不会存在问题,具体关于单例类的使用网上的文章已经很多了。

二、谨慎使用try catch

 我们在日常开发的时候会遇到一些我们无法解决的crash问题,或者说是不容易处理的bug,很多小伙伴估计会考虑使用try catch的方法将异常捕获,从而达到程序正常运行并且crash率也会较低,但是如果处理的不是很恰当的话也会导致内存泄漏问题。这段时间在检查程序内存泄漏问题的时候就发现了这样一个问题;通过WindowsManager对象添加一个View并显示出来,但是在跑monkey的时候不知道在什么情况下出现了crash问题,由于很难复现这个问题,也没有很好的定位到问题所在,所以我的小伙伴就想着直接try catch。但是,这个时候问题来了,通过MAT我发现了下面的问题

合理释放创建的线程

在开发应用的时候,为了处理耗时的操作时我们一般会启动新的线程,如果对这些线程不能很好的处理的话,也会带来相应的性能损耗。在查看性能时我也会通过android studio的monitor工具查看应用的线程数量和线程状态,如下图所示查看:

Android开发-细节决定性能_第2张图片
查看线程

 我通过该方法在查看团队开发的应用时,发现我进入某个页面的时候就会创建一个新的线程,而退出这个页面的时候该线程就处于等待状态,当我不停的进入退出就会有大量的线程处于等待状态,这个线程创建的位置也比较好定位,因为该线程的名字就是该类的名字(所以我建议在创建线程的时候最好可以setName,方便以后定位问题)。最终发现该类中创建了HandlerThread对象,该类的细节就不介绍了,当调用HandlerThread中的start方法的时候就会创建Looper对象并启动loop,阻塞等待Message消息。通过这个问题我先总结一下两点:

1.在利用HandlerThread创建线程的时候,当不在使用该线程的时候一定要调用quit或者quitSafely方法停止Looper的阻塞状态,从而释放Thread资源。

2.上面说的是关于HandlerThread,那么其他的还有没有?当然是有的,我记得在上一个团队的时候也发现是类似的问题,但是是启动的线程池。当时是启动的一个后台的Service干活,在该Service中启动的一个线程池,但是在退出Service时没有将该线程池释放,导致启动的线程池中的线程处于等待状态。当再次启动Service的时候又会创建线程线程池对象,启动新的线程,这样就容易造成资源的消耗。

如有问题欢饮讨论,后面继续补充其他!

你可能感兴趣的:(Android开发-细节决定性能)