内存优化
一、内存优化的目的
Android系统给每个app分配的内存是有限的,各个厂商分配的内存大小自己定制,可在清单文件中设置android:largeheap = "true"申请大内存,内存优化的目的主要是:
- Android系统内存不足时,会先杀死后台进程中内存比较大的应用
- 内存占用比较高时,会引起频繁的gc,gc过程会停止所有工作线程,导致界面卡顿
- 内存溢出时会导致应用奔溃,内存泄漏可能会导致频繁gc,最终可能导致内存溢出。
内存溢出是否可以捕获?OutofMemoryError是一种错误,不是异常,是虚拟机本身出错了,对于设计良好的应用程序来说,需要考虑的是如何避免出现这种情况,而不是情况出现了怎么解决。
在某些情况下,我们需要事先评估那些可能发生OOM的代码,对于这些可能发生OOM的代码,加入catch机制,可以考虑在catch里面尝试一次降级的内存分配操作。例如decode bitmap的时候,catch到OOM,可以尝试把采样比例再增加一倍之后,再次尝试decode。
OOm是否可以try catch
二、内存优化的手段
可以从四个方面着手,首先是减小对象的内存占用,其次是内存对象的重复利用,然后是避免对象的内存泄露,最后是内存使用策略优化。
1、减小对象的内存占用
- 使用ArrayMap/SparseMap代替HashMap
ArrayMap与HashMap相比是以时间换空间:
空间:对一个节点Entry<key,value>来说,ArrayMap保存了key的hash,key,value,而由于HashMap处理hash冲突使用的是链表法,所以多了next,下个节点的引用。
时间:ArrayMap使用二分查找,时间复杂度是O(logN),hashMap使用Hash查找,时间复杂度O(1),另外,ArrarMap的每次插入操作几乎都要整体移动数组,HashMap则不用。 - 避免使用枚举
底层实现是继承枚举类并new创建几个对象,使用int或者String代替枚举。
https://blog.csdn.net/lmj623565791/article/details/79278864 - 减小Bitmap的内存占用:图片压缩
1、尺寸压缩:inSampleSize
Bitmap需要高效加载
2、质量压缩:解码格式,选择ARGB-8888、RBG-565、ARGB-4444、ALPHA-8,存在很大差异,比如:ARGB-8888格式的图片,每像素占用 4 Byte,而 RGB-565则是 2 Byte。
2、内存对象的重复利用
- 使用Message.obtain()而不是new Message(),实现消息的复用
- ListView复用ConvertView
- Bitmap对象的复用:使用LRU
3、避免对象的内存泄露
- Activity的泄漏
1、匿名内部类导致(Handler、AsyncTask,Thread或Runnable)
解决方法:静态内部类+弱引用
2、Activity引用被传到别的实例中:单例模式
解决方法:传Context时使用Application代替Activity - 资源对象未关闭:BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源,使用后未关闭会导致内存泄漏。因为资源性对象往往都用了一些缓冲,缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外。如果仅仅是把它的引用置null,而不关闭它们,也会造成内存泄漏。
https://www.jianshu.com/p/f35ca324c285
三、内存优化工具
1、LeakCanary的使用和原理
LeakCanary用于监控Activity/Fragment是否发生内存泄漏。一般来说Activty销毁的时候,也就是调用onDestory后,垃圾回收时Activty对象必须被回收,没有的话就说明发生了内存泄漏。LeakCanary是怎样检测某个Activity是否发生内存泄漏的呢?Application中有个方法registerActivityLifecycleCallbacks(),用于监听Activity的生命周期。当监听到Activity调用onDestroy()的时候,通过一个弱引用保存当前Activity对象,并传入一个ReferenceQueue 。引用队列的作用是当引用指向的对象被垃圾回收时,会把引用放入到引用队列中。如果没有放进去,则说明发生了内存泄漏。LeakCanary接着会生成内存快照,并进行分析,找到GC Roots到Activity的引用路径,然后以发送通知的形式告知客户结果。
https://www.jianshu.com/p/3f1a1cc1e964
https://www.jianshu.com/p/70de36ea8b31
2、MAT的使用
以判断某个Activity是否泄漏为例说明MAT的使用方法:
假设现在要确定ActivtityA是否发生了泄漏,那么就先退出ActivityA,手动GC几次,然后生成内存快照,把内存快照放到MAT中进行分析,接着搜索ActivityA,查看Activity是否还存在在内存中,存在的话查看是否有到Gc Root的引用路径,有的话就能知道存在内存泄漏,内存泄漏发生在什么地方。
https://blog.csdn.net/yxz329130952/article/details/50288145
https://blog.csdn.net/junhuahouse/article/details/79731529
https://www.cnblogs.com/ldq2016/p/6632377.html
3、其他工具使用
Memory monitor
https://www.cnblogs.com/ldq2016/p/6628311.html
参考资料
腾讯Bugly Android 内存优化总结&实践
胡凯 Android内存优化之OOM
鸿洋 性能优化专题
Android性能全面分析与优化方案研究—几乎是史上最全最实用的
Android APP 性能优化的一些思考
Android应用开发进阶之性能优化
实践App内存优化:如何有序地做内存分析与优化