概述
最近在分析一个内存占用问题,就通过 AS 的 Memory Profile
(卡是真的卡)去查看了一下内存情况,看到了两个 Size,官方解释:
- Shallow Size:
Total amount of Java memory used by this object type (in bytes); Size of this instance in Java memory.
- Retained Size:
Total size of memory being retained due to all instances of this class (in bytes); Size of memory that this instance dominates (as per the dominator tree).
类似下图(业务代码的分析不方便贴出,随手写的 Demo 代码):
这篇文章我们再复习一下 Shallow Size
和 Retained Size
这两个概念,在此之前需要对 Java GC
机制有一定的了解,以前有记录过这块的内容,有兴趣可以参考看看 Java 垃圾回收机制。需要注意一下 GC Root
,它们不会被 GC 回收,典型的 GC Root
就是静态变量,被 GC Root
直接 or 间接引用的对象也不会被回收。
Shallow Size
Shallow Size
是指实例自身占用的内存,不包括它引用的其他实例。即:
Shallow Size = 类定义 + 属性占用空间 + 位数对齐
在我的 64 位机器上测试如下:
类定义
:声明一个类本身所需的空间,固定为 8 个字节。类定义空间不会重复计算,即使类继承了其他类,也只算 8 个字节。定义了一个没有任何属性的类,查看其Shallow Size
大小为 8 个字节。属性占用空间
:所有属性所占空间之和,包括自身的和父类的所有属性。属性分为基本类型和引用,如 int 类型占 4 个字节,long 类型占 8 个字节,引用固定 (String, Reference) 占 4 个字节。位数对齐
:使总空间为 8 的倍数。比如某个类以上两项共 21 字节,那么为了对齐,会取最接近 8 的倍数的值,即它的Shallow Size
是 24 个字节。与系统有关,有的不会对齐。
上面给出的截图,类结构如下,可以看出它就没有 位数对齐
这一项:
// Shallow Size = 28 = 8 + 4 + 8 + 4 + 4
// Retained Size = 36 = 28 + 8
data class Resource(
val int: Int,
val long: Long,
val string: String,
val reference: Res
)
// Shallow Size = 8
class Res()
Retained Size
Retained Size
是指某个实例被回收时,可以同时被回收的实例的 Shallow Size
之和。
因此在进行内存分析时,我们需要重点关注 Retained Size
较大的实例;另外也可以通过 Retained Size
判断出某个实例内部使用的实例是否被其他实例引用,比如说如果某个实例的 Retained Size
比较小,Shallow Size
比较大,说明它内部使用的某个实例还在其他地方被引用了(比如说对 Bitmap 实例而言,如果它的 Retained Size
很小,可以说明它内部的 byte 数组被另外的 Bitmap 实例复用了)。
举个栗子
现在有几个实例的引用关系如下图,假设每个实例的 Shallow Size
都为 X:
分别考虑回收这四个实例后,能释放的空间,即 Retained Size
大小,我们简单把某个实例 A 的 Retained Size
记作 R(A),Shallow Size
记作 S(A)。
- 移除 D 实例:D 没有引用任何实例,因此只会释放自身的
Shallow Size
,即R(D) = S(D) = X
。 - 移除 C 实例:移除 C 后,由于它引用了 D,且 D 没有被其他实例引用,因此 D 也会被一起回收,即
R(C) = S(C) + S(D) = 2X
。 - 移除 B 实例:移除 B 后,由于 B 和 A 实例都引用了 C 实例,所以移除 B 并不会让 C 实例被 GC 回收。即
R(B) = S(B) = X
。 - 移除 A 实例:B、C、D 实例被一起回收,即
R(A) = S(A) + S(B) + S(C) + S(D) = 4X
。
写在最后
在写这篇文章的时候翻了一些网上的博客,许多都是抄来抄去,或者说法各一,上面的数据经过了我自己的测试,发现 Shallow Size 具体大小的计算这里跟网上有些说法不太一致,有了解这块的同学可以评论区交流。
文中内容如有错误欢迎指出,共同进步!更新不易,觉得不错的留个赞再走哈~
Android视图系统:Android 视图系统相关的底层原理解析,看完定有收获。
Kotlin专栏:Kotlin 学习相关的博客,包括协程, Flow 等。
Android架构学习之路:架构不是一蹴而就的,希望我们有一天的时候,能够从自己写的代码中找到架构的成就感,而不是干几票就跑路。工作太忙,更新比较慢,大家有兴趣的话可以一起学习。
Android实战系列:记录实际开发中遇到和解决的一些问题。
Android优化系列:记录Android优化相关的文章,持续更新。