保留大小计算包括堆栈帧变量?
Retained size calculation including stack frame variables?
我在 "retained size" 上发现了很多问题,accepted answer 似乎是:
The retained size for an object is the quantity of memory this objects preserves from garbage collection.
现在,我一直致力于 hprof
文件中保留大小的编程计算(定义为 here), using the 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 进行计算的方式?如果上一个问题的答案是 "no"?
,我将如何添加这样的功能?
一点挖掘发现 JVM 堆转储程序为堆栈局部变量创建了一个 ROOT JAVA FRAME
类型的条目(比较 VM_HeapDumper::do_thread)。由于我可以在堆中进行 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根] id 是存储条目数据的一部分)。
与 Yourkit 的值相比仍有细微差别,可能是因为我缺少 ROOT JNI LOCAL
个实体,但对我来说已经足够接近了。
我在 "retained size" 上发现了很多问题,accepted answer 似乎是:
The retained size for an object is the quantity of memory this objects preserves from garbage collection.
现在,我一直致力于 hprof
文件中保留大小的编程计算(定义为 here), using the 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 进行计算的方式?如果上一个问题的答案是 "no"?
,我将如何添加这样的功能?一点挖掘发现 JVM 堆转储程序为堆栈局部变量创建了一个 ROOT JAVA FRAME
类型的条目(比较 VM_HeapDumper::do_thread)。由于我可以在堆中进行 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根] id 是存储条目数据的一部分)。
与 Yourkit 的值相比仍有细微差别,可能是因为我缺少 ROOT JNI LOCAL
个实体,但对我来说已经足够接近了。