是基於彼得Dolberg的答案,可以在VisualVM OQL控制檯中使用下列內容:
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實例包含一個條目,每個條目的值爲比相同String的前一條目大1的count
值。 然後將結果排序的count
場,結果看起來是這樣的:
{
count = 1028.0,
string = *null*
}
{
count = 1027.0,
string = *null*
}
{
count = 1026.0,
string = *null*
}
...
(在我的測試字符串"*null*"
是最常見的)。
最後一步是使用函數對其進行過濾,該函數在每個String的第一次出現時返回true。它使用數組來跟蹤哪些字符串已包含在內。
謝謝,很好地解決了這個問題。 oql在某種程度上使用起來很尷尬。這一切都必須發生在一個功能... – paweloque
哇,不知道jvisualvm是如此強大。我發現某些字符串的計數值很高 - 您的代碼是否排除垃圾(未引用的字符串)? – Jan
它使用「heap.objects」來查找堆中的所有java.lang.String對象。沒有過濾來排除未引用的字符串。但是,根據堆轉儲的生成方式,JVM可能在之前執行了完整的GC,在這種情況下,任何未引用的字符串應該已經被刪除並且不包含在堆轉儲中。 –