Android优化-内存优化总结篇

作者: 开飞机的老舒克 | 来源:发表于2017-12-08 16:29 被阅读42次

    一、Android内存管理机制

    1、Java对象的生命周期

    Java对象的生命周期经历7个阶段,分别是创建阶段、应用阶段、不可见阶段、不可达阶段、收集阶段、终结阶段、对象控件重新分配阶段。

    2、内存回收机制

    内存的三个区域

    内存会有三个区域,Yong Generation(年轻代)、Old Generation(年老代)、permanent Generation(持久代)。
    其中年轻代里面又分为三个区,eden、S0、S1。

    内存的处理过程:

    1.对象创建后在Eden区域,

    2.执行GC时,如果对象仍然存货,则复制到S0区。

    3.当S0区满时,改区域存活对象将复制到S1区,然后S0清空,接下来S0和S1角色互换。

    4.当第三部达到一定次数后,存活对象将被复制到Old Generation。

    5.当这个对象在Old Generation区域挺溜的时间达到一定程度时,它会被移动到Old Generation,最后积累一定时间再移动到Permaent Generation区域,Permaent Generation区域也存放一些静态文件。

    GC回收的一些算法

    Copying算法:扫描出存活的对象,并复制到一块新的完全未使用的控件中,对应于Young Generation,就是在Eden、FromSpace或ToSpace之间copy。

    标记算法:扫描出存活对象,然后再回收未标记的对象,回收后对空出的空间要么合并,要么标记出来便于下次分配,以减少内存碎片带来的损耗。年老代对象存活时间较长较稳定,使用标记算法回收。

    GC类型

    1.kGcCauseForAlloc:在分配内存时内存不够情况下引起的GC,这种情况下GC会stop World。Stop World 是由于并发GC时,其他线程都会停止。

    2.kGcCauseBackground:当内存达到一定阈值的时候引发GC,这个时候是一个后台GC,不会引起Stop World。

    3.kGcCauseExplicit:显示调用时进行的GC,如果ART打开了这个选项,在system.gc时会进行GC。

    其他GC注意事项

    1.尽量不去显式调用 system.gc() 减少不必要的系统开销,影响应用的流畅度。

    2.尽量减少内存泄露,避免OOM。

    二、Android内存泄露

    1、什么是内存泄露?

    java对象有自己的生命周期,当这个对象不需要再使用时,应该完整地走完生命周期,但因为某些原因,对象虽然已经不再使用,仍然在内存中并没有结束整个生命周期,这就意味着这个对象已经泄露了。

    GC会选择一些还存活的对象作为内存遍历的根节点 GC Roots,通过对GC Roots的可达性来判断是否需要回收。


    Android系统虚拟机的垃圾回收是通过虚拟机GC机制来实现的。GC会选择一些存活的对象作为内存便利的跟节点GC Roots,通过判断GC Roots的可达性来判断是否需要回收,如上图其中 1 2 3 4直接或间接被GC Roots引用链相连,这类对象被认为还需要使用的对象,就不会被回收。5 6 7将会被回收。到那时这里如果Object4 如果不需要使用的话这时候也不会被回收,就属于内存泄露。

    2、常见内存泄露场景以及注意事项

    ~ 资源型对象未关闭
    ~ 注册对象未注销
    ~ 类的静态变量持有大数据对象 如bitmap
    ~ 费静态内部类的静态实例
    ~ Handler临时性内存泄露
    ~ 容器中的对象没有清理造成的内存泄露

    3、内存泄露分析工具

    leakcanary

    三、常见注意事项避免内存消耗过多

    1、AutoBoxing自动装箱过程

     Integer num=0;   
     for(int i=0;i<100;i++){
         num+=i;
    ​​}​​
    

    这段代码每次循环,虚拟机都必须创建一个新的整数对象,并把它加到其他整数对象前面,创建一个新的整数对象,意味着要消耗更多性能。int只有4字节,而Integer对象有16字节。

    2、内容复用

    1、有效利用系统自带资源。
    2、视图复用,如ViewHolder。
    3、对象池。
    4、Bitmap对象复用。

    3、使用最优的数据类型

    1、当对象的数目在1000以内且特别多访问而删除和插入不高的时候尽量用ArrayMap替代HashMap。
    2、枚举的最大优点是安全、易读,但是内存消耗是定义常量的三倍以上。可以使用注解方式来检查安全。
    3、使用IntDef和StringDef检查类型安全。
    4、LruCache建议使用这个缓存机制,但是既不能分配太大,也不能分配太小。

    4、图片的内存优化

    设置位图规格,使用inSampleSize实现位图缩放和压缩。使用缓存机制等。

    四、内存分析工具

    1、Memory Monitor

    这个是一个我们开发过程中很常用的内存、CPU、网络的分析工具。


    Memory Monitor界面视图

    界面很直观,左上角有运行的机型和项目包名,然后最直观的动态图,分别是CPU、Memory、NetWork。点进去可以进入的Memory。


    Memory Monitor的Memory局部视图
    这里可以清晰的看到颜色对应区域占用的内存大小。
    Memory Monitor的Memory整体视图

    通过这两张图 内存的大部分信息都能查阅到。我们在操作APP加载图片等操作时候能看到内存上升、和下降,如果操作APP后发现内存不会下降可能就是我们有些对象没有及时释放,也有可能导致内存泄露。
    还有对应的模拟GC,查看时间段具体内存信息以及一段时间的内存追踪等工具可以使用。可以定位到具体的代码行。如下图:


    具体类详细内存信息展示
    这里有一个Shallow size这个属性的概念:
    Shallow size就是对象本身占用内存的大小,不包含其引用的对象。常规对象(非数组)的Shallow size有其成员变量的数量和类型决定。数组的shallow size有数组元素的类型(对象类型、基本类型)和数组长度决定。

    2、Heap Viewrer

    Heap Viewrer工具视图界面

    如果是Android Studio的话通过Tools->Android->Android Device Monitor找到这个工具。
    进入后选择运行APP的包名然后点击update Heap按钮,这时候会在每次gc时展示数据信息,也可以在后面手动GC,如果在操作页面这时候可能会发现小卡顿,因为在GC时,可能导致其他线程停止工作,这时可以清晰看到表中内存信息:
    头部总览视图:

    标题 含义
    Heap Size 堆栈分配给APP的内存大小。
    Allocated 已分配使用的内存大小。
    Free 空闲的内存大小。
    %Used Allocated/Heap Size 的使用率。
    #Object 对象数量

    下面详情视图:

    标题 含义
    free 空闲的对象
    data object 数据对象,Java类类型对象,是最主要的观察对象。
    class object java类类型的引用对象。
    1-byte array(byte[],boolean[]) 一字节的数组对象。
    2-byte array(short[],char[]) 两字节的数组对象。
    4-byte array(object[],int[],float[]) 4字节的数组对象。
    8-byte array(long[],double[]) 8字节的数组对象。
    non-java object 非Java对象。

    每个类型的数据值对应:

    标题 含义
    Count 数量
    Total Size 总共占用的内存的大小
    Smallest 将对象占用内存从小到大排列,排在第一个对象占用内存大小
    Largest 将对象占用内存从小到大排列,排在最后一个对象占用的内存大小。
    Median 将对象占用内存从小到大排列,排在总监的对象占用的内存大小。
    Average 平均值

    相关文章

      网友评论

      本文标题:Android优化-内存优化总结篇

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