Android开发经验谈Android技术知识Android开发

Shallow Size和Retained Size详解

2019-08-17  本文已影响4人  AssIstne

Shallow Size和Retained Size详解

参考文章
How much memory do I need (part 1) – What is retained heap?

How much memory do I need (part 2) – What is shallow heap?

在Android开发中, 想要进行内存分析, 总会看见Shallow SizeRetained Size, 这边文章主要解释

  1. 它们分别表示什么含义
  2. 它们是如何计算出来的

Java garbage collection (GC)

我们先了解GC的一些基本知识

  1. 程序中存在一些实例, 称作GC root, 它们不会被GC回收, 常见的例如静态变量, 线程等
  2. GC root直接或间接引用的实例会被标记为in use, 它们也不会被GC回收

Shallow Size

Shallow Size是指实例自身占用的内存, 可以理解为保存该'数据结构'需要多少内存, 注意不包括它引用的其他实例

计算公式:

Shallow Size = [类定义] + 父类fields所占空间 + 自身fields所占空间 + [alignment]
  1. 类定义是指, 声明一个类本身所需的空间, 固定为8byte, 也就是说, 一个不包含任何fields的类的'空类', 也需要占8byte; 另外类定义空间不会重复计算, 就是说, 即使类继承其他类, 也只算8byte
  2. 父类fields所占空间, 对于继承了其他类的类来说, 父类声明的fields显然需要占用一定的空间
  3. 自身fields所占空间, 所有fields所占空间之和; fields分基本类型和引用, 基本类型所占空间和系统有关, 例如在32位系统中int=4byte, 64位系统中int=8byte; 引用固定占4byte, 例如String name;这个变量声明占4byte.
  4. 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为:

  1. 类定义的8byte
  2. 没有继承其他类, 所以没有父类fields
  3. 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为:

  1. 类定义的8byte
  2. 继承了X类, X类的所有fields为X类的Shallow Size减去类定义空间8byte, 也就是17byte-8byte=9byte
  3. 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例子

RetainedSize例子.png

图中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实例的情况

上一篇下一篇

猜你喜欢

热点阅读