Android 内存优化简介

作者: 梦飞成2012 | 来源:发表于2016-04-17 19:31 被阅读4597次

    1、内存占用高导致的问题

    • 1、内存泄漏导致OOM崩溃
    • 2、界面卡顿,影响用户体验
    • 3、高内存耗电,被系统及安全软件警告,容易被卸载或后台关闭

    之所以要内存优化为了更好的适应JVM的GC机制,减少对程序的影响(减少卡顿)。

    2、JVM 内存模型

    Minor GC
    使用标记-清除-复制算法,将Eden区和From Survivor区中存活下来的对象复制到 To Survivor区中,然后清空Eden区和From Survivor区,速度快。

    Major GC
    采用标记-清除-压缩算法,即,先标记无用的对象,然后将存活下来的对象移动,整理碎片,以腾出更大的连续空间。

    如下图所示:

    JVM.png

    3、GC原理及简介

    采用是否根节点可访问判断是否需要回收对象,如下图所示

    GC.png
    3.1标记清除复制算法
    mark-copy.png
    3.2标记清除复制算法
    mark-press.png

    4、GC Reason和Name

    Reason
    Concurrent----后台回收内存,不暂停用户线程
    
    Alloc----当app要申请内存,而堆又快满了的时候,会阻塞用户线程
    
    Explicit----调用Systemt.gc()等方法的时候触发,一般不建议使用
    
    NativeAlloc----当native内存有压力的时候触发
    
    Name
    Concurrent mark sweep----全部对象的检测回收
    Concurrent partial mark sweep----部分的检测回收
    Concurrent sticky mark sweep----仅检测上次回收后创
    建的对象,速度快,卡顿少,比较频繁
    

    GC log 示例

    04-06 09:41:48.541 5021-5045/com.husor.beibei I/art: Background partial concurrent mark sweep GC freed 22647(1359KB) AllocSpace objects, 5(969KB) LOS objects, 6% free, 53MB/57MB, paused 5.128ms total 68.744ms
    

    5、如何进行内存优化

    • 1、消除内存泄漏
    • 2、使用高性能编程
    • 3、降低程序运行的内存占用

    6、常见内存泄漏和高内存占用原因

    • 1、慎重使用static变量
    • 2、长周期内部类、匿名内部类长时间持有外部类引用导致相关资源无法释放(Handler或者内部线程等)
    • 3、BitMap导致内存溢出
    • 4、数据库、文件流等没有关闭
    • 5、监听器、广播注册后没有及时注销
    • 6、Adapter没有使用convertView
    • 7、字符串拼接尽量使用StringBuilder或者StringBuffer
    • 8、避免内存抖动,例如不要在onDraw中创建对象。
    • 9、界面不可见时,停止动画和相关线程
    6.1、示例一:
    sample1.png

    原因:
    sBackground, 是一个静态的变量,但是我们发现,我们并没有显式的保存Contex的引用,但是,当Drawable与View连接之后,Drawable就将View设置为一个回调,由于View中是包含Context的引用的,所以,实际上我们依然保存了Context的引用。这个引用链如下:Drawable->TextView->Context

    解决办法:

    第一,应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。 
    第二、Context尽量使用Application Context,因为Application的Context的生命周期比较长
    第三、使用WeakReference代替强引用。比如WeakReference<Context> mContextRef; (已经不推荐)
    
    6.1、示例二:
    sample2.png

    原因:

    Activity退出后,其实例并未被回收。因为OneThread作为非静态内部类还持有BasicActivity的实例。

    解决方案:

    1、OneThread改为静态内部类
    2、如果OneThread需要Context实例,使用弱引用保存它。
    3、如果有必要,在BasicActivity的OnDestroy里面关闭线程
    

    7、内存分析工具

    7、1 Android Monitor
    util1.png

    ** 优点:**
    使用简单,直观显示当前app的内存变化
    缺点:
    无法具体定位内存问题,只能给出内存笼统的变化。
    常用于分析内存变化趋势。

    7、2 Allocation Tracker
    util2.png
    1、选择进程,在合适的实际开始和结束追踪。
    2、Studio会自动打开文件,里面展示这一段时间内内存的分配情况,可以分析自己的程序哪里内存占用比较高,是否有大量的相同类型的 Object 被分配和释放。如果有,则其可能引起性能问题。
    
    7、3 MAT

    步骤:

    • 1生成mat文件

    在android studio 生成dump文件,并转为标准dump。
    如下图所示

    mat1.png mat2.png
    • 2使用mat分析
    • 以内部线程导致内存泄漏为例分析:
      1、多次打开该demo,生成dump文件
      2、打开MAT工具,选择“File”>>“open heap dump”,打开dump文件
      3、打开后在,“Action”里的“Histogram”,然后搜索SecondActivity
    mat3.png
    • 3猜测分析原因

      通过上面看到,存在11个SecondActivity的实例,有点诡异。
      选择SecondActivity这一项,然后右键“Merge Shortest Paths to GC Roots ”>>"exclude all phantom/weak/soft etc references.."

    mat4.png mat5.png
    7、4LeakCanary 检测内存泄漏
    leakcanary.png

    直接可以通过通知栏看到内存泄露的地方

    LeakCanary参考资料:
    https://github.com/square/leakcanary
    http://blog.csdn.net/watermusicyes/article/details/46333925
    http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/

    相关文章

      网友评论

        本文标题:Android 内存优化简介

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