Shallow Size和Retained Size详解

转自 https://www.jianshu.com/p/851b5bb0a4d4

在Android开发中, 想要进行内存分析, 总会看见Shallow Size和Retained 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例子

在这里插入图片描述

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值