美文网首页
内存优化

内存优化

作者: 编程的猫 | 来源:发表于2021-08-31 22:52 被阅读0次

    内存对于Android应用来说是一种稀缺资源,系统分配给每一进程的内存大小有限,虽然Java本身就自带内存回收机制,但是在写代码的过程中如果没有内存回收的意识,还是很容易出现内存泄漏,严重可能可能会导致内存抖动,甚至发生OOM内存溢出的Crash。
    【内存抖动是由于短时间产生大量的零时对象,此时维持程序运行的可支配内存不足,导致频繁的GC,在GC的时候除了GC线程所有线程都会挂起,这会表现出应用卡顿,反复重复上述过程就是内存抖动】
    所以内存优化是必要性的!

    内存问题:

    内存抖动:短时间内产生大量零时对象,触发频繁GC。
    内存泄漏:本应该被回收的对象,却被无意义的持有了引用导致无法GC回收释放。
    内存溢出:要求从虚拟机申请一块内存,但是可支配内存不足时就会发生内存溢出。内存溢出很多时候都是由于内存泄漏堆积导致的,还有申请内存使用不当。

    要不要写详细点?

    有必要了解的知识,Java虚拟机内存模型,在java虚拟机中内存分为5块区域:
    虚拟机栈:Java方法调用执行的管理区域(一个栈帧对应一个方法,栈帧的入栈出栈对应着一个方法的调用)。
    本地方法栈:Native(C、C++)方法对应的栈帧管理,同java。
    程序计数器:对应着程序字节码的执行行数计数,在Thread切换的时候负责记录程序执行的位置。
    【以上三块内存区域是线程私有的,下边两块是线程公用的内存区域,GC也是发生在这两块】
    方法区:存放对象引用、静态成员、常量。
    堆:对象存放的区域,也是GC的主要发生地,也是五块内存区域中最大的一块内存区域。

    当发生GC的时候,会去回收堆中可回收的对象。堆分为两块区域,新生代和老年代,分别执行者不同的内存管理算法。
    新生代(存放朝生暮死的对象):(hotspot虚拟机在新生代内存分为8:1:1)

    1. 标记-整理算法
      将还存活的对象全部压缩到一块区域,剩下区域的都是可回收的对象,将被回收。
    2. 标记-清除算法
      在标记-整理算法中,还存活的对象都将年龄标记计算加一。
    3. 复制整理算法
      在新生代中标记的年龄达到阈值的时候,将被复制到老年代,说明这中对象是kennel长时间存在的。
      老年代(存放生命长久的对象):
    4. 标记整理算法
      没有被引用的就回收掉,还存活的就压缩到内存的一块区域,保证内存的连续性,缓解碎片化问题。
    5. 标记-清除算法
      没有被引用的就回收掉。

    哪些对象是被判定可回收对象?
    从GC Roots对象往下追溯,没有引用链可达的对象都是可被回收的对象。
    可以作为GC Roots根节点的对象:常量池中常量引用的对象、栈中本地方法表成员引用的对象、静态成员引用的对象。

    Java虚拟机内存这块额外多了解了解。。。

    内存分析工具
    1. Android Studio自带的Memory Profile
      Memory Profile能够很直观的帮助我们分析代码运行中内存的使用情况。


      profile
    image.png

    app heap:这一列展示了内存中所存在的这些类
    Allocations:是分配了多少对象
    Native Size:主要反映Bitmap所使用的像素内存
    Shallow Size:该实例的大小
    Retained Size:该实例所支配的内存大小

    1. LeakCanary开源库
      LeakCanary可以很方便的帮助我们在App开发测试阶段发现内存了泄漏。
      在build.gradle添加依赖
    //LeakCanary
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.2'
    releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2'
    

    在Application的onCreate方法中初始化

    if (!LeakCanary.isInAnalyzerProcess(this)) {
         LeakCanary.install(this);
    }
    

    然后当你的App中出现内存泄露时,手机桌面会出现一个Leaks的图标,点击进去可以看到产生泄露的记录列表,点击列表条目可以展开具体的泄露信息:


    图片来自一叶难障目
    LeakCanary原理

    弱引用被回收时,引用会被添加到引用队列。
    给被监控的对象分为一个UUID,并存储到set集合中。使用弱引用对被监控的对象进行包装,然后主动调用GC,在GC执行完毕后遍历引用队列对应移除set集合中的UUID,没有被移除的UUID对应的对象就被判定是存在内存泄漏的对象。

    内存优化的策略
    1. 善用线程池。
    2. 善用对象池复用对象。
    3. Bitmap图片资源压缩,用完及时回收释放内存。
    4. 注册器、数据库游标记得及时回收。
    5. LargeHeap属性申请更多的内存(虽然有点耍流氓,但还是应该向系统申请)。
    6. onTrimMemory、onLowMemory(系统给的低内存的回调,可以根据不同的回调等级去处理一些逻辑)。
    7. 使用一些内存优化后的特定数据结构,例如:SparseArray、ArrayMap。

    相关文章

      网友评论

          本文标题:内存优化

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