使用 MAT 时的 Shallow Size 和 Retained Size 的区别

编者注:本文为历史博文归档;涉及 JDK、框架与工具链版本请以当前官方文档为准。引用外链图片可能失效,阅读时请注意时效性。

所有具备 Heap Profiling(堆分析)功能的工具(如 MAT、Yourkit、JProfiler、TPTP 等)都会涉及两个核心概念:Shallow SizeRetained Size

这两个概念在日常开发中并不常见,但它们对于理解内存占用至关重要。本文将对这两个名词进行详细解释。

Shallow Size

Shallow Size 指的是对象自身占用的内存大小,不包括它引用的其他对象。

  • 非数组类型对象:大小等于对象头与它所有成员变量大小的总和。这其中还包括一些 Java 语言特性的数据存储单元(如对象头信息)。
  • 数组类型对象:大小是数组元素对象的大小总和。

Retained Size

Retained Size 的计算公式如下:

Retained Size = 当前对象大小 + 当前对象可直接或间接引用到的对象的大小总和
  • 间接引用的含义:若存在引用链 A -> B -> C,则 C 是 A 的间接引用对象。
  • 实际意义:Retained Size 代表当前对象被 GC(垃圾回收)后,从 Heap(堆)上总共能释放掉的内存。

注意:在计算释放内存时,需要排除被 GC Roots 直接或间接引用的对象,因为这些对象暂时不会被当做 Garbage(垃圾)回收。

图解 Retained Size

通过下图可以更直观地理解 Retained Size 的计算逻辑。

Shallow size and retained size

在上图中,GC Roots 直接引用了 AB 两个对象:

  • A 对象的 Retained Size = A 对象的 Shallow Size
  • B 对象的 Retained Size = B 对象的 Shallow Size + C 对象的 Shallow Size

这里不包括 D 对象,因为 D 对象被 GC Roots 直接引用,即使 B 被回收,D 依然存在。

如果 GC Roots 不引用 D 对象呢?

Shallow Size and retained size

此时,引用关系发生变化:

  • B 对象的 Retained Size = B 对象的 Shallow Size + C 对象的 Shallow Size + D 对象的 Shallow Size

参考资料

转载自:http://kenwublog.com/understand-shallow-and-retained-size-in-hprofling