背景
在阅读本文之前可先了解一下原来写过的一篇关于堆的文章:jvm堆
java堆内存里面存放着各种对象,而大部分我们的对象存放于堆中,但堆又分为浅堆和深堆,主要区别于堆的大小和被GC回收后,可以释放内存的大小。
浅堆(Shallow Head)是什么?
浅堆指一个对象所消耗的内存,当在32位系统中,一个对象引用会占据4个字节(32位),比如一个Int类型的对象会占据4个字节,而long类型的变量会占8个字节,每个对象头都会占据8个字段,由于堆的快照格式不同,对象的大小可能存在同8字节进行对齐。(JDK7)
大小计算:浅堆大小 = 对象头 + 实例数据 + 对齐填充
对象类型 | 名称 | 占用字节 |
---|---|---|
int | hash32 | 4 |
int | hash | 4 |
ref | value | 8 |
head | 对象头 | 8 |
padding | 填充 | 4 |
比如:一个StrIng 里面有2个int 共占8个字节,对象引用占4个字节,对象头占用8个字节,填充头 4个字段,总共24个字节,这24就是最终这个浅堆的大小。
注意这里,浅堆的引用可能引用了非常多的对象,这里浅堆不需要关心,仅计算该引用的大小固定为4,而深堆才关心具体引用内容大小。
深堆(Retained Heap)是什么?
在了解深堆之前需要先了解一下保留集(Retained Set),指对象被垃圾回收后,可以被释放所有对象的集合,即对仅能通过对象引用到的直接或间接的所有对象的集合。
个人理解:比如下面的A、B、C、D、E,其中A引用了 C D 而B 引用了D E,只能通过A直接或间接引用的用只有C,而只能通过B直接或间引用只有E,其中D是被共用,所以不被任何一个对象占有,所以B不属于任保一个保留集。
了解以上的保留集,再来了解深堆就很简单了,深堆指对象的保留集所有的对象浅堆大小的总和。
深堆大小:对象本身+指向的保留集
比如:B的大小是:B+E
对象实际大小计算:浅堆大小+引用的大小
比如:B的实际在小是 B+ D+ E
注意:以上的浅堆、深堆、对象实际大小计算各不相同;
最后
浅堆和深堆在面试中,经常会用来提前面试者,这两者有什么区别,有什么关系,怎么计算大小等。对于我们来说,除了可能面试会用上,实际开发过程中,也有很好的学习作用,比如太多的引用你会发现OOM,这种溢出或者泄露的问题排查以及代码的鲁棒性是不是更佳等,以及使用一个内存分析工具经常也会用来进行分析的指标,比如MAT、jprofiler等。
参考文章:
https://www.imooc.com/article/317274
https://my.oschina.net/aidelingyu/blog/1602341