我想构建一个 OQL 查询,使用该查询从特定包中的类中递归打印出 JVM 堆转储的所有静态数据。我知道递归遍历内存引用可能存在很多问题,但是(至少在最初)我会通过设置深度阈值来缓解这些问题。
根据文档,类有一个statics
字段,该字段又应由name
s 和s组成value
:
statics - 类的静态字段的名称、值对。
我已经停止使用表达式获取每个静态字段的名称,field.name
并且不知道如何迭代对象的非静态字段。我目前有:
select map(
filter(
filter(heap.classes(), "/com.heap./.test(it.name)"),
function (clazz) {
if (clazz.statics) {
return true;
}
return false;
}
), function (clazz) {
var res = '';
res += toHtml(clazz.name) + " : " + toHtml(clazz.statics) + "<br>";
map(clazz.statics, function (field) {
res += "--" + toHtml(field) + "," + toHtml(field.name) + "," + toHtml(field.state) +"<br>";
});
return res + "<br>";
}
)
并得到以下输出:
com.heap.dump.DataHolder : { :sun.misc.Launcher$AppClassLoader#1, }
--sun.misc.Launcher$AppClassLoader#1,null,null
com.heap.dump.HeapDumperTest : { dataHolder:com.heap.dump.DataHolder#1, mutableStaticState:java.lang.String#225, :sun.misc.Launcher$AppClassLoader#1, }
--com.heap.dump.DataHolder#1,null,java.lang.String#224
--java.lang.String#225,null,null
--sun.misc.Launcher$AppClassLoader#1,null,null
com.heap.dump.Main : { :sun.misc.Launcher$AppClassLoader#1, }
--sun.misc.Launcher$AppClassLoader#1,null,null
我正在迭代clazz.statics
使用该map()
函数,遵循这个答案。
看起来field
参数只是字段的值,field.name
一如既往null
并且field.state
实际上检索对象之一(com.heap.dump.DataHolder.state
)上的字段。
主要问题:
- 在迭代静态字段时,除了值之外,如何获取字段名称?
- 一旦有了要遍历的对象/实例,如何迭代该对象的非静态字段(名称和值)?这种获取字段值的方法,就像
field.state
语句一样,只有在我已经知道字段名称的情况下才有帮助,这里不是这种情况。
附加问题:
- 如何过滤掉空名称的 AppClassLoader 静态字段?
- 我是否使用了错误的工具来完成这项工作?VisualVM 的 OQL 是否有更简单的替代方案?