[-] java
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/42238627 android
有很多朋友都问过我,怎样才能写出高性能的应用程序,如何避免程序出现OOM,或者当程序内存占用太高的时候该怎么样去排查。确实,一个优秀的应用程序,不只仅要功能完成得好,性能问题也应该处理得恰到好处。为此,我也是阅读了很多Android官方给出的高性能编程建议,那么从本篇文章开始,我就准备开始写一个全新系列的博文,来把这些建议进行整理和分析,帮助你们可以写出更加出色的应用程序。 程序员
注意本系列文章的内容基本源于Android Doc,若是想要阅读更加详细的关于性能方面的资料,能够直接去阅读Android官方文档。 编程
内存(RAM)对于任何一个软件开发环境都是种很是珍贵的资源,而对于移动操做系统来说的话,则会显得更加珍贵,由于手机的硬件条件相对于PC毕竟是比较落后的。尽管Android系统的虚拟机拥有自动回收垃圾的机制,但这并不表明咱们就能够忽视应该在何时分配和释放内存。 缓存
为了使垃圾回收器能够正常释放程序所占用的内存,在编写代码的时候就必定要注意尽可能避免出现内存泄漏的状况(一般都是因为全局成员变量持有对象引用所致使的),而且在适当的时候去释放对象引用。对于大多数的应用程序而言,后面其它的事情就能够都交给垃圾回收器去完成了,若是一个对象的引用再也不被其它对象所持有,那么系统就会将这个对象所分配的内存进行回收。 网络
咱们在开发软件的时候应当自始至终都把内存的问题充分考虑进去,这样的话才能开发出更加高性能的软件。而内存问题也并非无规律可行的,Android系统给咱们提出了不少内存优化的建议技巧,只要按照这些技巧来编写程序,就可让咱们的程序在内存性能发面表现得至关不错,下面咱们就来一一学习一下这些技巧。 app
若是应用程序当中须要使用Service来执行后台任务的话,请必定要注意只有当任务正在执行的时候才应该让Service运行起来。另外,当任务执行完以后去中止Service的时候,要当心Service中止失败致使内存泄漏的状况。 框架
当咱们启动一个Service时,系统会倾向于将这个Service所依赖的进程进行保留,这样就会致使这个进程变得很是消耗内存。而且,系统能够在LRU cache当中缓存的进程数量也会减小,致使切换应用程序的时候耗费更多性能。严重的话,甚至有可能会致使崩溃,由于系统在内存很是吃紧的时候可能已没法维护全部正在运行的Service所依赖的进程了。 ide
为了可以控制Service的生命周期,Android官方推荐的最佳解决方案就是使用IntentService,这种Service的最大特色就是当后台任务执行结束后会自动中止,从而极大程度上避免了Service内存泄漏的可能性。关于IntentService更加详细的用法讲解,能够参考《第一行代码——Android》的9.5.2节。 工具
让一个Service在后台一直保持运行,即便它并不执行任何工做,这是编写Android程序时最糟糕的作法之一。因此Android官方极度建议开发人员们不要过于贪婪,让Service在后台一直运行,这不只可能会致使手机和程序的性能很是低下,并且被用户发现了以后也有可能直接致使咱们的软件被卸载(我我的就会这么作)。
当用户打开了另一个程序,咱们的程序界面已经再也不可见的时候,咱们应当将全部和界面相关的资源进行释放。在这种场景下释放资源可让系统缓存后台进程的能力显著增长,所以也会让用户体验变得更好。
那么咱们如何才能知道程序界面是否是已经不可见了呢?其实很简单,只须要在Activity中重写onTrimMemory()方法,而后在这个方法中监听TRIM_MEMORY_UI_HIDDEN这个级别,一旦触发了以后就说明用户已经离开了咱们的程序,那么此时就能够进行资源释放操做了,以下所示:
除了刚才讲的TRIM_MEMORY_UI_HIDDEN这个回调,onTrimMemory()方法还有不少种其它类型的回调,能够在手机内存下降的时候及时通知咱们。咱们应该根据回调中传入的级别来去决定如何释放应用程序的资源:
以上是当咱们的应用程序正在运行时的回调,那么若是咱们的程序目前是被缓存的,则会收到如下几种类型的回调:
当咱们读取一个Bitmap图片的时候,有一点必定要注意,就是千万不要去加载不须要的分辨率。在一个很小的ImageView上显示一张高分辨率的图片不会带来任何视觉上的好处,但却会占用咱们至关多宝贵的内存。须要仅记的一点是,将一张图片解析成一个Bitmap对象时所占用的内存并非这个图片在硬盘中的大小,可能一张图片只有100k你以为它并不大,可是读取到内存当中是按照像素点来算的,好比这张图片是1500*1000像素,使用的ARGB_8888颜色类型,那么每一个像素点就会占用4个字节,总内存就是1500*1000*4字节,也就是5.7M,这个数据看起来就比较恐怖了。
至于如何去压缩图片,以及更多在图片方面节省内存的技术,你们能够去参考我以前写的一篇博客 Android高效加载大图、多图解决方案,有效避免程序OOM 。
Android API当中提供了一些优化事后的数据集合工具类,如SparseArray,SparseBooleanArray,以及LongSparseArray等,使用这些API可让咱们的程序更加高效。传统Java API中提供的HashMap工具类会相对比较低效,由于它须要为每个键值对都提供一个对象入口,而SparseArray就避免掉了基本数据类型转换成对象数据类型的时间。
咱们还应当清楚咱们所使用语言的内存开支和消耗状况,而且在整个软件的设计和开发当中都应该将这些信息考虑在内。可能有一些看起来无关痛痒的写法,结果却会致使很大一部分的内存开支,例如:
许多程序员都喜欢各类使用抽象来编程,认为这是一种很好的编程习惯。固然,这一点不能否认,由于的抽象的编程方法更加面向对象,并且在代码的维护和可扩展性方面都会有所提升。可是,在Android上使用抽象会带来额外的内存开支,由于抽象的编程方法须要编写额外的代码,虽然这些代码根本执行不到,可是却也要映射到内存当中,不只占用了更多的内存,在执行效率方面也会有所下降。固然这里我并非提倡你们彻底不使用抽象编程,而是谨慎使用抽象编程,不要认为这是一种很酷的编程方式而去肆意使用它,只在你认为有必要的状况下才去使用。
如今有不少人都喜欢在Android工程当中使用依赖注入框架,好比说像Guice或者RoboGuice等,由于它们能够简化一些复杂的编码操做,好比能够将下面的一段代码:
ProGuard相信你们都不会陌生,不少人都会使用这个工具来混淆代码,可是除了混淆以外,它还具备压缩和优化代码的功能。ProGuard会对咱们的代码进行检索,删除一些无用的代码,而且会对类、字段、方法等进行重命名,重命名以后的类、字段和方法名都会比原来简短不少,这样的话也就对内存的占用变得更少了。
这个技巧其实并非很是建议使用,但它确实是一种能够帮助咱们节省和管理内存的高级技巧。若是你要使用它的话必定要谨慎使用,由于绝大多数的应用程序都不该该在多个进程当中运行的,一旦使用不当,它甚至会增长额外的内存而不是帮咱们节省内存。这个技巧比较适用于那些须要在后台去完成一项独立的任务,和前台的功能是能够彻底区分开的场景。
这里举一个比较适合去使用多进程技巧的场景,好比说咱们正在作一个音乐播放器软件,其中播放音乐的功能应该是一个独立的功能,它不须要和UI方面有任何关系,即便软件已经关闭了也应该能够正常播放音乐。若是此时咱们只使用一个进程,那么即便用户关闭了软件,已经彻底由Service来控制音乐播放了,系统仍然会将许多UI方面的内存进行保留。在这种场景下就很是适合使用两个进程,一个用于UI展现,另外一个则用于在后台持续地播放音乐。
想要实现多进程的功能也很是简单,只须要在AndroidManifest文件的应用程序组件中声明一个android:process属性就能够了,好比说咱们但愿播放音乐的Service能够运行在一个单独的进程当中,就能够这样写:
这里指定的进程名是background,你也能够将它改为任意你喜欢的名字。须要注意的是,进程名的前面都应该加上一个冒号,表示该进程是一个当前应用程序的私有进程。
遵循以上的全部编程建议,咱们就可让应用程序内存的使用变得更加合理化。但这只是第一步而已,为了要让程序拥有最佳性能,咱们要学习的东西还有不少,下篇文章当中将会介绍如何分析内存的使用状况,感兴趣的朋友请继续阅读 Android最佳性能实践(二)——分析内存的使用状况 。