转自 https://www.jianshu.com/p/851b5bb0a4d4
在Android开发中, 想要进行内存分析, 总会看见Shallow Size和Retained Size, 这边文章主要解释
- 它们分别表示什么含义
- 它们是如何计算出来的
Java garbage collection (GC)
我们先了解GC的一些基本知识
- 程序中存在一些实例, 称作GC root, 它们不会被GC回收, 常见的例如静态变量, 线程等
- 被GC root直接或间接引用的实例会被标记为in use, 它们也不会被GC回收
Shallow Size
Shallow Size是指
实例自身占用的内存
, 可以理解为保存该'数据结构'需要多少内存
, 注意不包括它引用的其他实例
计算公式:
Shallow Size = [类定义] + 父类fields所占空间 + 自身fields所占空间 + [alignment]
- 类定义是指, 声明一个类本身所需的空间,
固定为8byte
, 也就是说, 一个不包含任何fields的类的’空类’, 也需要占8byte; 另外类定义空间不会重复计算, 就是说,即使类继承其他类, 也只算8byte
- 父类fields所占空间, 对于继承了其他类的类来说, 父类声明的fields显然需要占用一定的空间
- 自身fields所占空间, 所有fields所占空间之和; fields分基本类型和引用, 基本类型所占空间和系统有关, 例如在32位系统中int=4byte,
64位系统中int=8byte
;引用固定占4byte
, 例如String name;这个变量声明占4byte. - alignment是指位数对齐,
会让总空间为8的倍数
, 例如某个A类, 以上3项计算出来为15byte, 那么为了对齐, 让它是8的倍数, 会取最接近的值, 所以它的Shallow Size是16byte;
注意, alignment行为和JVM有关, 对于Android来说, 实测4.4系统会有对齐行为, 但是5.1系统不会
Shallow Size例子
class X {
int a;
byte b;
Integer c = new Integer();
}
假设当前是在32位系统, 对于类X来说, 一个X实例的Shallow Size为:
- 类定义的8byte
- 没有继承其他类, 所以没有父类fields
- a变量为int型, 4byte; b变量为byte型, 1byte; c变量是引用类型, 和它是否指向具体实例无关, 固定占4byte
如果不算alignment,
X的Shallow Size = 8 + 0 + 4 + 1 + 4 = 17byte
如果算上alignment, 那么要补齐为8的倍数, 也就是24byte.
class Y extends X {
List d;
Date e;
}
一个Y实例的Shallow Size为:
- 类定义的8byte
- 继承了X类, X类的所有fields为
X类的Shallow Size减去类定义空间8byte
, 也就是17byte-8byte=9byte - d, e都是引用类型, 各占4byte
如果不算alignment,
Y的Shallow Size = 8 + 9 + 4 + 4 = 25byte
如果算上alignment, 那么要补齐为8的倍数, 也就是32byte.
Retained Size
实例A的Retained Size是指,
当实例A被回收时
,可同时被回收的实例的Shallow Size之和
所以进行内存分析时应重点关注Retained Size较大的实例
; 或者可以通过Retained Size判断出某A实例内部使用的实例是否被其他实例引用.
例如在Android中, 如果某个Bitmap实例的Retained Size很小, 证明它内部的byte数组被复用了, 有另一个Bitmap实例指向了同一个byte数组
.
Retained Size例子
图中A, B, C, D四个实例, 为了方便计算, 我们假设所有实例的Shallow Size都是1kb
D实例
D实例没有引用其他实例, 所以移除D实例只会释放它自己的空间, 因此
D实例的Retained Size=Shallow Size=1kb
C实例
当我们移除C实例, C实例引用了D实例, 同时D实例没有被其他实例引用, 所以D实例也会被GC
, 所以
C实例的Retained Size = C实例的Shallow Size + D实例的Shallow Size = 2kb
B实例
当我们移除B实例, 虽然B实例引用了C实例, 但是A实例也引用了C实例, 所以移除B实例不会让C实例被GC
, 所以
B实例的Retained Size=Shallow Size=1kb
A实例
当我们移除A实例, 显然A, B, C, D实例都会被GC
, 所以
A实例的Retained Size=4kb
总结
计算Retained Size的关键在于领会移除实例时, 可以同时被回收的实例
, 重点观察B实例的情况