Нижеследующее основано на ответе Питера Долберга и может быть использовано в консоли OQL VisualVM :
var counts={};
var alreadyReturned={};
filter(
sort(
map(heap.objects("java.lang.String"),
function(heapString){
if( ! counts[heapString.toString()]){
counts[heapString.toString()] = 1;
} else {
counts[heapString.toString()] = counts[heapString.toString()] + 1;
}
return { string:heapString.toString(), count:counts[heapString.toString()]};
}),
'lhs.count < rhs.count'),
function(countObject) {
if( ! alreadyReturned[countObject.string]){
alreadyReturned[countObject.string] = true;
return true;
} else {
return false;
}
}
);
Все начинается с вызова map()
по всей строкеэкземпляры и для каждой строки, создавая или обновляя объект в массиве counts
.Каждый объект имеет поля string
и count
.
Полученный массив будет содержать одну запись для каждого экземпляра String, каждый из которых будет иметь значение count
на единицу больше, чем предыдущая запись для той же строки.Затем результат сортируется в поле count
, и результат выглядит примерно так:
{
count = 1028.0,
string = *null*
}
{
count = 1027.0,
string = *null*
}
{
count = 1026.0,
string = *null*
}
...
(в моем тесте строка "*null*"
была наиболее распространенной).
последний шаг - отфильтровать это с помощью функции, которая возвращает true для первого вхождения каждой строки.Он использует массив alreadyReturned
, чтобы отслеживать, какие строки уже были включены.