我有一个29G堆转储,由OutOfMemoryError
发生后由Hotspot VM创建。堆分析器(我使用YourKit)显示所有对象(包括不可达对象)都占用26G。我的猜测是剩余的3G被浪费了,因为堆是零散的。有没有办法检查这个理论?
答案 0 :(得分:3)
这与堆碎片无关。
大小的差异由堆转储格式解释。请注意,堆转储不是堆的原始内容,而是以HPROF格式对内容进行序列化表示。
因此,每个对象实例都由具有以下结构的s
记录表示:
HPROF_GC_INSTANCE_DUMP
考虑一个u1 record tag
u8 object ID
u4 stack trace serial number
u8 class ID
u4 number of bytes that follow
u1* <field data>
的实例。在64位压缩的OOPs HotSpot JVM中,java.lang.Integer
的实例占用16个字节:8个字节的标头+ 4个字节的类指针+ 4个字节的Integer
字段。同一实例在堆转储中将占用29个字节,从而产生81.25%的巨大开销。
当然,在典型的Java应用程序中,堆通常充满了更大的对象,即数组。这就是为什么HPROF记录标头的平均开销看起来较小(大约10%)的原因,就像您的情况一样。