更好的方法来识别没有收集垃圾的对象?

juh*_*nic 8 java debugging garbage-collection jvm jhat

简而言之

我有一个程序,随着时间的推移逐渐使用越来越多的内存.我正在使用jmap和jhat来尝试和诊断它,但我仍然不是那里.

背景

该程序是一个长期运行的服务器,由hbase数据存储区支持,为许多其他东西提供thrift服务.但是,运行几天之后,它最终将达到分配的堆限制,并且几乎所有时间都在垃圾收集中来回晃动.似乎引用会被保存到某个地方的大量数据中

到目前为止我做了什么

在摆弄jstat和jconsole之后,我最终得到了运行进程的jmap的heapdumps,并通过jhat运行它,并且数字简单不会累加到内存利用率附近的任何地方

jmap -F -dump:live,format=b,file=heap.dump 12765

jmap -F -dump:format=b,file=heap.all 12765

直方图顶部的一些东西

Class   Instance Count  Total Size
class [B     7493    228042570
class java.util.HashMap$Entry    2833152     79328256
class [Ljava.util.HashMap$Entry;     541     33647856
class [Ljava.lang.Object;    303698  29106440
class java.lang.Long     2851889     22815112
class org.apache.hadoop.hbase.KeyValue   303593  13358092
class org.apache.hadoop.hbase.client.Result  303592  9714944
class [I     14074   9146580
class java.util.LinkedList$Entry     303841  7292184
class [Lorg.apache.hadoop.hbase.KeyValue;    303592  7286208
class org.apache.hadoop.hbase.io.ImmutableBytesWritable  305097  4881552
class java.util.ArrayList    302633  4842128
class [Lorg.apache.hadoop.hbase.client.Result;   297     2433488
class [C     5391    320190
Run Code Online (Sandbox Code Playgroud)

虽然这里的总数并没有加起来,但是在进行堆转储时,进程使用了​​超过1GB的内存.

直接明显的罪魁祸首似乎是我在整个地方留下了HBase Result和KeyValue条目.试图追踪引用,我最终命中了

Object at 0x2aab091e46d0

instance of org.apache.hadoop.hbase.ipc.HBaseClient$Call@0x2aab091e46d0 (53 bytes)

Class:

class org.apache.hadoop.hbase.ipc.HBaseClient$Call
Instance data members:

done (Z) : true
error (L) : <null>
id (I) : 57316
param (L) : org.apache.hadoop.hbase.ipc.HBaseRPC$Invocation@0x2aab091e4678 (48 bytes) 
this$0 (L) : org.apache.hadoop.hbase.ipc.HBaseClient@0x2aaabfb78f30 (86 bytes) 
value (L) : org.apache.hadoop.hbase.io.HbaseObjectWritable@0x2aab092e31c0 (40 bytes) 
References to this object:

Other Queries

Reference Chains from Rootset
Exclude weak refs
Include weak refs
Objects reachable from here
Run Code Online (Sandbox Code Playgroud)

需要帮助:

似乎没有引用这个最终的HBaseCLient $ Call对象(或任何其他类似的对象,每个对象持有大约一千个关键值及其所有内部数据).不应该得到GCed?我只是误解了gc的工作方式或jhat验证引用的程度?如果是这样,我还能做些什么来追踪我的"缺失"记忆?我可以采取哪些其他步骤来追踪这一点?

Law*_*Dol 0

我建议首先尝试 JVisualVM,它随最新的 JDK 一起分发。

另外,如果你能证明成本合理的话,多年来我发现 JProfiler 是一个出色的工具。