Java-анализ кучи с oql: подсчет уникальных строк
Im делает анализ памяти существующего программного обеспечения Java. Существует ли sql 'group by' эквивалент в oql, чтобы увидеть количество объектов с одинаковыми значениями, но в разных экземплярах.
выберите count (*)
из java.lang.String s
group by s.toString()
Я хотел бы получить список дублированных строк вместе с количеством дубликатов. Цель этого - увидеть случаи с большими числами, чтобы их можно было оптимизировать с помощью String.intern().
Пример:
"foo" 100
"bar" 99
"lazy fox" 50
и т.д...
Ответы
Ответ 1
Ниже приводится ответ Питера Дольберга и может быть использован в VisualVM OQL Console:
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()
по всем экземплярам String и для каждой строки, создающей или обновляющей объект в массиве counts
. Каждый объект имеет поле string
и count
.
Результирующий массив будет содержать одну запись для каждого экземпляра String, каждый из которых имеет значение count
, большее, чем предыдущая запись для той же строки.
Затем результат сортируется в поле count
, и результат выглядит примерно так:
{
count = 1028.0,
string = *null*
}
{
count = 1027.0,
string = *null*
}
{
count = 1026.0,
string = *null*
}
...
(в моем тесте строка "*null*"
была наиболее распространенной).
Последний шаг - отфильтровать это, используя функцию, которая возвращает true для первого вхождения каждой строки. Он использует массив alreadyReturned
, чтобы отслеживать, какие строки уже были включены.
Ответ 2
Вместо этого я использовал бы Eclipse Memory Analyzer.
Ответ 3
К сожалению, в OQL нет эквивалента "group by". Я предполагаю, что вы говорите об OQL, который используется в jhat и VisualVM.
Есть альтернатива. Если вы используете чистый синтаксис JavaScript вместо синтаксиса "select x from y", то у вас есть полная работоспособность JavaScript для работы.
Тем не менее, альтернативный способ получения информации, которую вы ищете, не прост. Например, здесь OQL "запрос", который выполнит ту же задачу, что и ваш запрос:
var set={};
sum(map(heap.objects("java.lang.String"),function(heapString){
if(set[heapString.toString()]){
return 0;
}
else{
set[heapString.toString()]=true;
return 1;
}
}));
В этом примере обычный JavaScript-объект имитирует набор (коллекция без дубликатов). Поскольку функция карты проходит через каждую строку, этот набор используется для определения того, была ли строка уже просмотрена. Дубликаты не учитываются в общей сумме (return 0), но новые строки (return 1).
Ответ 4
Более эффективный запрос:
var countByValue = {};
// Scroll the strings
heap.forEachObject(
function(strObject) {
var key = strObject.toString();
var count = countByValue[key];
countByValue[key] = count ? count + 1 : 1;
},
"java.lang.String",
false
);
// Transform the map into array
var mapEntries = [];
for (var i = 0, keys = Object.keys(countByValue), total = keys.length; i < total; i++) {
mapEntries.push({
count : countByValue[keys[i]],
string : keys[i]
});
}
// Sort the counts
sort(mapEntries, 'rhs.count - lhs.count');
Ответ 5
Просто отправьте мое решение и опыт при выполнении аналогичной проблемы для других ссылок.
var counts = {};
var alreadyReturned = {};
top(
filter(
sort(
map(heap.objects("java.lang.ref.Finalizer"),
function (fobject) {
var className = classof(fobject.referent)
if (!counts[className]) {
counts[className] = 1;
} else {
counts[className] = counts[className] + 1;
}
return {string: className, count: counts[className]};
}),
'rhs.count-lhs.count'),
function (countObject) {
if (!alreadyReturned[countObject.string]) {
alreadyReturned[countObject.string] = true;
return true;
} else {
return false;
}
}),
"rhs.count > lhs.count", 10);
В предыдущем коде будут представлены 10 лучших классов, используемых java.lang.ref.Finalizer.
Советы:
1. Функция сортировки с помощью функции XXX НЕ работает на моей Mac OS.
2. Функция класса может возвращать класс референта. (Я пытался использовать fobject.referent.toString() → , это вернуло много org.netbeans.lib.profiler.heap.InstanceDump. Это также потратило много времени).
Ответ 6
Способ 1
Вы можете выбрать все строки, а затем использовать терминал для их агрегирования.
- Увеличьте лимит oql в конфигурационных файлах visual vm
- перезагрузить визуальный вм
- oql, чтобы получить все строки
- скопируйте и вставьте их в VIM
- очистить данные с помощью макросов Vim, так что
-
sort | uniq -c
sort | uniq -c
чтобы получить количество.
Способ 2
- Используйте инструмент для сброса всех объектов полей интересующего вас класса (https://github.com/josephmate/DumpHprofFields может это сделать)
- Используйте bash для выбора интересующих вас строк
- Используйте bash для агрегирования