使用 oql 进行 java 堆分析:对唯一字符串进行计数

2022-09-03 04:29:26

我正在对现有的java软件进行内存分析。oql中是否有等效的sql'group by',以查看具有相同值但不同实例的对象的计数。

从 java.lang.String s group by s.toString() 中选择 count(*)

我想获得重复字符串的列表以及重复字符串的数量。这样做的目的是查看具有大量数字的案例,以便可以使用String.intern()对其进行优化。

例:

"foo"    100
"bar"    99
"lazy fox"    50

等。。。


答案 1

以下内容基于Peter 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;
    }
   }
  );

它首先对所有 String 实例使用调用,并为每个 String 创建或更新数组中的对象。每个对象都有一个和一个字段。map()countsstringcount

生成的数组将包含每个 String 实例的一个条目,每个条目的值都比同一 String 的上一个条目大一个。然后,在字段上对结果进行排序,结果如下所示:countcount

{
count = 1028.0,
string = *null*
}

{
count = 1027.0,
string = *null*
}

{
count = 1026.0,
string = *null*
}

...

(在我的测试中,字符串是最常见的)。"*null*"

最后一步是使用一个函数对此进行筛选,该函数为每个 String 的第一次出现返回 true。它使用数组来跟踪已包含哪些字符串。alreadyReturned


答案 2

我会改用Eclipse Memory Analyzer


推荐