Eclipse MAT(Memory Analyzer Tool)是一种分析堆转储的强大工具。当您尝试调试与内存相关的问题时,它非常方便。在Eclipse MAT中,报告了两种类型的对象大小:
-
浅堆
-
保留堆
在本文中,让我们研究它们之间的区别并探索它们的计算方法
图1:内存中的对象
通过示例学习新概念更容易。假设您的应用程序有一个对象模型,如图#1所示:
-
对象A持有对象B和C的引用。
-
对象B持有对象D和E的引用。
-
对象C持有对象F和G的引用。
假设每个对象占用10个字节的内存。现在,有了这个背景,让我们开始我们的研究。
浅堆大小
记住:对象的浅堆是它在内存中的大小。因为在我们的示例中,每个对象占用大约10个字节,所以每个对象的浅堆大小为10个字节。非常简单。
保留B的堆大小
从图#1中,您可以注意到对象B持有对象D和E的引用。因此,如果对象B是从内存中收集的垃圾,则对象D和E将不再有活动引用。这意味着D和E可以也是垃圾收集。保留堆是特定对象被垃圾回收时将释放的内存量。因此,B的保留堆大小是:
= B的浅堆大小+ D的浅堆大小+ E的浅堆大小
= 10个字节+10个字节+10个字节
= 30个字节
因此,B的保留堆大小是30个字节。
保留C的堆大小
对象C持有对象F和G的引用。因此,如果对象C是从内存中收集的垃圾,则不再有对象F和G的引用。这意味着F和G也可以被垃圾收集。但是,C的保留堆大小是:
= C的浅堆大小+ F的浅堆大小+ G的浅堆大小
= 10个字节+10个字节+10个字节
= 30个字节
因此,C的保留堆大小也是30个字节。
图2:对象浅和保留的堆大小
保留A的堆大小
对象A持有对象B和C的引用,而对象B和C依次保持对对象D,E,F和G的引用。因此,如果对象A是从内存中收集的垃圾,则不再有对象的引用B,C,D,E,F和G.通过这种理解,让我们完成A的保留堆大小计算。
因此,A的保留堆大小是:
= A的浅堆大小+ B的浅堆大小+ C的浅堆大小+ D的浅堆大小+ E的浅堆大小+ F的浅堆大小+ G的浅堆大小
= 10字节+10字节+10字节+10字节+10字节+10字节+10字节
= 70个字节
然后我们可以得出结论,A的保留堆大小是70个字节。
保留堆D,E,F和G的大小
D的保留堆大小是10个字节,但是,这仅包括它们的浅大小。这是因为D不保存任何其他对象的任何活动引用。因此,如果D收集垃圾,则不会从内存中删除其他对象。根据相同的解释对象,E,F和G的保留堆大小也只有10个字节。
让我们的研究更有趣
现在,让我们的研究更有趣一点,这样您就可以深入了解浅堆和保留的堆大小。让对象H开始在示例中保持对B的引用。注意对象B已被对象A引用。现在,两个人A和H持有对对象B的引用。在这种情况下,让我们研究一下我们保留的堆计算会发生什么。
图3:对象B的新引用
在这种情况下,对象A的保留堆大小将减少到40个字节。奇怪?百思不得其解?
如果对象A被垃圾收集,那么将不再有对象C,F和G的引用。因此,只有对象C,F和G将被垃圾收集。另一方面,对象B,D和E将继续存在于存储器中,因为H持有对B的有效引用。因此,即使A被垃圾收集,也不会从存储器中移除B,D和E.
因此,A的保留堆大小是:
= A的浅堆大小+ C的浅堆大小+ F的浅堆大小+ G的浅堆大小
= 10个字节+10个字节+10个字节+10个字节
= 40个字节。
A的总保留堆大小将变为40个字节。保留堆大小的所有其他对象将保持不受干扰,因为它们的引用没有变化。
希望本文有助于澄清Eclipse MAT中的Shallow堆大小和保留堆大小计算。您还可以考虑探索HeapHero - 另一个功能强大的堆转储分析工具,它显示由于低效的编程实践(例如对象重复,数据结构的过度分配和利用不足,次优数据类型定义等)而浪费的内存量。
另外本人从事在线教育多年,将自己的资料整合建了一个公众号,对于有兴趣一起交流学习java可以微信搜索:“程序员文明”,里面有大神会给予解答,也会有许多的资源可以供大家学习分享,欢迎大家前来一起学习进步!