获取从大小为 1 的 ArrayList 中引用的对象数,按 class 分组
Get number of objects referenced from ArrayList with size 1 grouped by class
我从应用程序中获得了堆转储,发现有大量 ArrayLists,其中只有 1 个对象。我知道如何获取此类数组列表的列表并显示包含元素的 class:
SELECT list.elementData[0] FROM java.util.ArrayList list WHERE (list.size = 1)
结果如下所示:
java.lang.String [id=0x7f8e44970]
java.lang.String [id=0x7f8e44980]
java.lang.String [id=0x7f8e44572]
java.io.File [id=0x7f8e43572]
...
我想要得到这样的东西:
Class | count
=================================
java.lang.String | 100
java.io.File | 74
...
但我无法汇总结果或对这些结果执行任何其他操作。我找到了 here 如何将值传递给外部 select,但我不知道如何在第一个 select 中使用除 *
之外的任何其他内容。
SELECT * from OBJECTS
(SELECT OBJECTS list.elementData[0] FROM java.util.ArrayList list WHERE (list.size = 1))
VisualVM's OQL 中没有 group by
但是您可以使用内置函数制作一个 JavaScript 代码段并 运行 它在 "OQL Console":
var c = {};
/* Filter to show only the first occurence (max count) */
filter(
/* Sort by occurences desc */
sort(
/* Count class instances */
map(
heap.objects("java.util.ArrayList"),
function(list) {
var clazz = 'null';
if (list.size = 1 && list.elementData[0] != null) {
clazz = classof(list.elementData[0]).name;
}
c[clazz] = (c[clazz] ? c[clazz] + 1 : 1);
return { cnt:c[clazz], type:clazz };
}
), 'rhs.cnt - lhs.cnt'
),
function (item) {
if (c[item.type]) {
c[item.type] = false;
return true;
} else {
return false;
}
}
);
输出是一个对象数组,如:
{
cnt = 3854.0,
type = null
}
{
cnt = 501.0,
type = org.apache.tomcat.util.digester.CallMethodRule
}
{
cnt = 256.0,
type = java.lang.ref.WeakReference
}
{
cnt = 176.0,
type = sun.reflect.generics.tree.SimpleClassTypeSignature
}
最后,您可以再次调用 map
函数将输出格式化为其他格式,例如 exmpale as csv:
map(
filter(...),
'it.type + ", " + it.cnt'
);
输出:
null, 3854
org.apache.tomcat.util.digester.CallMethodRule, 501
java.lang.ref.WeakReference, 256
sun.reflect.generics.tree.SimpleClassTypeSignature, 176
org.apache.tomcat.util.digester.CallParamRule, 144
com.sun.tools.javac.file.ZipFileIndex$Entry, 141
org.apache.tomcat.util.digester.ObjectCreateRule, 78
我从应用程序中获得了堆转储,发现有大量 ArrayLists,其中只有 1 个对象。我知道如何获取此类数组列表的列表并显示包含元素的 class:
SELECT list.elementData[0] FROM java.util.ArrayList list WHERE (list.size = 1)
结果如下所示:
java.lang.String [id=0x7f8e44970]
java.lang.String [id=0x7f8e44980]
java.lang.String [id=0x7f8e44572]
java.io.File [id=0x7f8e43572]
...
我想要得到这样的东西:
Class | count
=================================
java.lang.String | 100
java.io.File | 74
...
但我无法汇总结果或对这些结果执行任何其他操作。我找到了 here 如何将值传递给外部 select,但我不知道如何在第一个 select 中使用除 *
之外的任何其他内容。
SELECT * from OBJECTS
(SELECT OBJECTS list.elementData[0] FROM java.util.ArrayList list WHERE (list.size = 1))
VisualVM's OQL 中没有 group by
但是您可以使用内置函数制作一个 JavaScript 代码段并 运行 它在 "OQL Console":
var c = {};
/* Filter to show only the first occurence (max count) */
filter(
/* Sort by occurences desc */
sort(
/* Count class instances */
map(
heap.objects("java.util.ArrayList"),
function(list) {
var clazz = 'null';
if (list.size = 1 && list.elementData[0] != null) {
clazz = classof(list.elementData[0]).name;
}
c[clazz] = (c[clazz] ? c[clazz] + 1 : 1);
return { cnt:c[clazz], type:clazz };
}
), 'rhs.cnt - lhs.cnt'
),
function (item) {
if (c[item.type]) {
c[item.type] = false;
return true;
} else {
return false;
}
}
);
输出是一个对象数组,如:
{
cnt = 3854.0,
type = null
}
{
cnt = 501.0,
type = org.apache.tomcat.util.digester.CallMethodRule
}
{
cnt = 256.0,
type = java.lang.ref.WeakReference
}
{
cnt = 176.0,
type = sun.reflect.generics.tree.SimpleClassTypeSignature
}
最后,您可以再次调用 map
函数将输出格式化为其他格式,例如 exmpale as csv:
map(
filter(...),
'it.type + ", " + it.cnt'
);
输出:
null, 3854
org.apache.tomcat.util.digester.CallMethodRule, 501
java.lang.ref.WeakReference, 256
sun.reflect.generics.tree.SimpleClassTypeSignature, 176
org.apache.tomcat.util.digester.CallParamRule, 144
com.sun.tools.javac.file.ZipFileIndex$Entry, 141
org.apache.tomcat.util.digester.ObjectCreateRule, 78