繁体   English   中英

VisualVM 堆转储“Summary”显示的根比“Objects->Preset: GC Roots”显示的多,这是什么意思?

[英]VisualVM heap dump "Summary" shows way more roots than "Objects->Preset: GC Roots" shows, what does it mean?

我怀疑由 JNI 代码引起的缓慢 memory 泄漏。 我在连续堆转储爬升的摘要中看到了 GC Roots #。 两个小时后,它显示了 470,000 个 GC 根,六个小时后,显示了近一百万个 GC 根,33 小时后显示了超过 700 万个 GC 根。

但是,当我查看说有 700 万个 GC 根的 Head Dump 时,我选择了“对象”视图和“GC 根”预设,我选择了 select 聚合“类型”。 此列表显示的对象总数少于 15,000 个:

  • JNI 全局 - 计数 7857
  • JNI 本地 - 计数 5
  • Java 帧 - 计数 983
  • 使用的显示器 - 计数 7
  • 粘性 class - 计数 3596
  • 线程 object - 计数 145

那七百万个根在哪里?

不同的 GC 根可以引用同一个 object 实例。 这解释了差异,因为从“GC root”视图计数显示的唯一实例数。 您可以使用 OQL 找到更多详细信息。 首先让我们显示特定 GC 类型的 GC 根数:

printHistogram()

function printHistogram() {
  var roots = heap.roots()
  var histoMap = new Array();
  var result = new Array();
  var cnt = 0;
 
  while (roots.hasMoreElements()) {
    var root = roots.nextElement();
    var type = root.type;
    if (histoMap[type] == undefined) {
      histoMap[type] = 1;
    } else {
      histoMap[type]++;
    }
  }
  for (var key in histoMap){
    if (histoMap.hasOwnProperty(key)) {
      result[cnt++] = { key: key, count: histoMap[key] };
  }
  return map(sort(result, "rhs.count - lhs.count"), '"Root count: "+it.count+" for type: "+it.key');
}

针对您的堆转储运行此查询会产生:

Root count: 12878043 for type: JNI local
Root count: 7858 for type: JNI global
Root count: 3599 for type: sticky class
Root count: 1631 for type: Java frame
Root count: 146 for type: thread object
Root count: 7 for type: monitor used

我们可以看到大多数 GC 根是“JNI 本地”类型。 让我们看看有多少“JNI 本地”根指向同一个 object 实例。 我们可以将上面的查询修改为:

printHistogram()

function printHistogram() {
  var roots = heap.roots()
  var histoMap = new Array();
  var result = new Array();
  var cnt = 0;

  while (roots.hasMoreElements()) {
    var root = roots.nextElement();
    if (root.type == "JNI local") {
      var objid = root.id;
      if (histoMap[objid] == undefined) {
        histoMap[objid] = 1;
      } else {
        histoMap[objid]++;
      }
    }
  }
  for (var key in histoMap){
    if (histoMap.hasOwnProperty(key)) {
      result[cnt++] = { key: key, count: histoMap[key] };
  }
}

return map(sort(result, "rhs.count - lhs.count"), '"Root count: "+it.count+" for object: "+toHtml(heap.findObject(it.key))');

}

结果如下:

Root count: 6439020 for object: java.lang.String#44429
Root count: 6439020 for object: java.lang.String#55081
Root count: 1 for object: java.nio.DirectByteBuffer#9
Root count: 1 for object: java.util.ArrayList#22281
Root count: 1 for object: java.lang.String#71518

我们可以看到两个字符串java.lang.String#44429java.lang.String#55081负责大量的 GC 根。 他们每个都有 650 万个 GC 根。

那些“JNI 本地”GC 根是从框架ca.digitalrapids.kayak.jni.KayakNativeWorkerThread.runNative (Native Method)MessageDispatherThread-1 (tid=216)引用的。 请参阅下面的屏幕截图:

堆栈跟踪

当地人

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM