内存(Memory)¶
为什么要做内存分析 ? 当内存不足会造成异常(oom,内存分配失败,llk,设备重启等)与卡顿(触发频繁的gc),而出现内存不足的原因有很多比如内存泄漏,为了减少oom与卡顿这个时候就需要分析内存从中找出优化点
虚拟机/引擎¶
- Android:art
- React Native/小程序:quickjs 、v8、hermes、javascriptcore,js引擎如何选型?
- Flutter:dart vm
术语¶
引用类型
- 强可及对象(strongly reachable):可以通过强引用访问的对象。
- 软可及对象(softly reachable):不是强可及对象,并且能够通过软引用访问的对象。
- 弱可及对象(weakly reachable):不是强可及对象也不是软可及对象,并且能够通过弱引用访问的对象。
- 虚可及对象(phantomly reachable):不是强可及对象、软可及对象,也不是弱可及对象,已经结束的,可以通过虚引用访问的对象。
清除:将引用对象的 referent 域设置为 null ,并将引用类在堆中引用的对象声明为可结束的。
Shallow Size:对象自身占用的内存大小,不包括它引用的对象
Retained Size:被GC后Heap上释放的内存大小,即当前对象大小+当前对象可直接或间接引用到的对象的大小总和
outgoing reference(当前对象引用的外部对象):查看对象为什么耗内存,我们看到一个线程池占用了>25mb的内存
ingoing reference(直接引用了当前对象的对象):查看对象被谁引用
gc root对象:
- 类(方法区静态成员变量引用的对象)
- 活动的Thread实例
- 局部变量或者方法参数变量持有的对象(java 虚拟机堆栈 、 本地方法堆栈)
- JNILocalReference引用的对象
- JNIGlobalReference引用的对象
- synchronize关键字用到的对象
分代垃圾算法¶
大部分的对象都是”朝生夕死”,经过几次gc之后就会被转移到老年代。新生代占内存区域的⅓而老年代占内存区域的⅔,新生代使用MinorGC,老年代使用MajorGC/FullGC回收整块堆
- 新生代(gc:MinorGC)
- 采用算法 :标记复制法(浪费预留区域的空间,如果遇到大量存活的对象,就需要频繁复制才能释放少量的空间,所以更适合新生代)
- 分区:Eden区 、S0区(survivor)、S1区(survivor) 比例为8:1:1,压缩了预留空间,从原来的½到1/10
-
存活的对象会在S0与S1之间来回移动,并且年龄累加1
-
老年代(gc:MajorGC)
- 采用的算法:标记清除算法(遇到大部分需要回收的对象时,执行效率不高;容易产生碎片化) or 标记整理算法(若存在大量存活对象,就需要移动更多的对象来换取少量的空间)
内存指标¶
- 内存异常率
- 内存触顶率:超过最大堆的85%限制,gc就会频繁,容易oom与卡顿