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

我发现了很多关于“保留大小”的问题, 接受的答案似乎是:

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

现在,我一直在使用Netbeans分析器库 (保留大小的计算在HprofHeap.java完成)在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是它的计算? 如果对上一个问题的答案是“否”,我将如何去添加这样的功能?

有一点挖掘发现,JVM堆翻斗为堆栈本地变量(比较VM_HeapDumper :: do_thread )创建ROOT JAVA FRAME类型的条目。 因为我可以在堆中找到这个问题,所以我做了以下工作:

 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实体,但对我来说足够接近。

Interesting Posts