美文网首页
内存优化

内存优化

作者: 细雨蒙情 | 来源:发表于2018-06-16 14:47 被阅读13次

    一、内存优化的目的

    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内存优化:如何有序地做内存分析与优化

    相关文章

      网友评论

          本文标题:内存优化

          本文链接:https://www.haomeiwen.com/subject/azxkeftx.html