保留大小计算,包括堆栈帧变量?

时间:2015-12-16 14:48:10

标签: netbeans jvm-hotspot hprof

我发现了大量关于“保留大小”的问题,accepted answer似乎是:

  

对象的保留大小是此对象从垃圾回收中保留的内存量。

现在,我一直在使用herehprof文件(定义为Netbeans profiler library)中的保留大小进行编程计算(保留的大小计算在HprofHeap.java)。工作得很好(抱歉,为了简洁使用kotlin):

val heap: Heap = HeapFactory.createHeap(myHeap.toFile())
val threadClass: JavaClass = heap.getJavaClassByName("java.lang.Thread")
val instanceFilter = { it: Instance -> threadClass == it.getJavaClass() }
val sizeMap = heap.allInstances
            .filter { instanceFilter(it) }
            .toMap({ findThreadName(it) /* not shown */ }, { it.retainedSize })

sizeMap仅保留大小的保留大小时,我注意到的是Netbeans仅为堆栈中的对象计算保留大小。因此,分配给Thread的局部变量(在堆栈上分配)将包含在保留大小中。

我的问题是:有没有办法让netbeans库将堆栈元素视为依赖对象,例如Yourkit Profiler进行计算?如果上一个问题的答案是“否”,我将如何添加这样的功能?

1 个答案:

答案 0 :(得分:2)

一些挖掘发现JVM堆转储器为堆栈局部变量(比较VM_HeapDumper::do_thread)创建了类型ROOT JAVA FRAME的条目。因为我可以在堆中grep,这就是我所做的:

val threadClass: JavaClass = heap.getJavaClassByName("java.lang.Thread")

val keyTransformer = { it: Instance -> findThreadName(it) }
val instanceFilter = { it: Instance -> it.getJavaClass() == threadClass }

val stackLocals = heap.gcRoots
        .filter { it.kind == GCRoot.JAVA_FRAME }
        .groupBy { (it as JavaFrameGCRoot).threadGCRoot }

val sizeMap = heap.allInstances
      .filter { instanceFilter(it) }
      .toMap(
          { keyTransformer(it) }, 
          { 
              val locals = stackLocals[heap.getGCRoot(it)]
              val localSize = locals!!.sumBy { it.instance.retainedSize.toInt() }
              it.retainedSize + localSize
          })

return Report(
        sizeMap.values.sum(),
        sizeMap.keys.size.toLong(),
        sizeMap.maxBy { it.value }?.let { it.toPair() } ?: ("n/a" to 0L))

此解决方案基于查找每个线程的GC根(应该是Thread本身),然后排序到JAVA FRAME的存储gc根(线程[= GC root] id是存储的条目数据的一部分。)

与Yourkit的值相比,还有一点点差异,可能是由于我错过了ROOT JNI LOCAL个实体,但它对我来说足够接近。