Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用oql的java堆分析:计数唯一字符串_Java_Performance_Memory_Heap - Fatal编程技术网

使用oql的java堆分析:计数唯一字符串

使用oql的java堆分析:计数唯一字符串,java,performance,memory,heap,Java,Performance,Memory,Heap,我正在对现有的java软件进行内存分析。oql中是否存在sql“group by”等效项,以查看具有相同值但不同实例的对象的计数 选择计数(*) 来自java.lang.String s s.toString()的分组 我想获得一个重复字符串的列表以及重复的数量。这样做的目的是查看具有大量数据的案例,以便可以使用String.intern()对其进行优化 例如: "foo" 100 "bar" 99 "lazy fox" 50 等等。遗憾的是,OQL中没有与“group by

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

选择计数(*) 来自java.lang.String s s.toString()的分组

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

例如:

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

等等。

遗憾的是,OQL中没有与“group by”等价的词。我假设你说的是jhat和VisualVM中使用的OQL

不过,还有一种选择。如果您使用纯JavaScript语法而不是“从y中选择x”语法,那么您就拥有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对象模拟一个集合(没有重复项的集合)。当map函数遍历每个字符串时,集合用于确定是否已经看到该字符串。重复项不计入总数(返回0),但新字符串计入总数(返回1)

我会改为使用。

以下内容基于Peter Dolberg的答案,可以在OQL控制台中使用:

var计数={};
var alreadyReturned={};
滤器(
分类(
映射(heap.objects(“java.lang.String”),
函数(堆字符串){
如果(!counts[heapString.toString()]){
计数[heapString.toString()]=1;
}否则{
计数[heapString.toString()]=计数[heapString.toString()]+1;
}
返回{string:heapString.toString(),count:counts[heapString.toString()]};
}), 
'lhs.count
它首先使用
map()
调用所有字符串实例,并为每个字符串创建或更新
counts
数组中的对象。每个对象都有一个
字符串
和一个
计数
字段

结果数组将为每个字符串实例包含一个条目,每个条目的
count
值比同一字符串的前一个条目大一个。 然后在
count
字段中对结果进行排序,结果如下所示:

{
count = 1028.0,
string = *null*
}

{
count = 1027.0,
string = *null*
}

{
count = 1026.0,
string = *null*
}

...
(在我的测试中,字符串
“*null*”
是最常见的)


最后一步是使用一个函数对此进行过滤,该函数在每个字符串的第一次出现时返回true。它使用
alreadyReturned
数组跟踪已包含的字符串

在处理类似问题时,只需发布我的解决方案和经验,以供其他参考

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);
前面的代码将输出java.lang.ref.Finalizer使用的前10个类。
提示:
1.使用XXX函数的排序功能在我的Mac OS上不起作用。

2.classof函数可以返回引用对象的类。(我尝试使用fobject.referent.toString()->这返回了很多org.netbeans.lib.profiler.heap.InstanceDump。这也浪费了我很多时间)。

一个更高效的查询:

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');
var countByValue={};
//滚动字符串
heap.forEachObject(
函数(strObject){
var key=strObject.toString();
var count=countByValue[key];
countByValue[键]=计数?计数+1:1;
},
“java.lang.String”,
假的
);
//将地图转换为数组
var mapEntries=[];
对于(var i=0,keys=Object.keys(countByValue),total=keys.length;i
方法1 您可以选择所有字符串,然后使用终端聚合它们

  • 增加visual vm配置文件中的oql限制
  • 重新启动可视虚拟机
  • oql获取所有字符串
  • 复制并粘贴到vim中
  • 使用vim宏清理数据,以便
  • sort | uniq-c
    获取计数
  • 方法2
  • 使用工具转储您感兴趣的类的所有字段对象(可以这样做)
  • 使用bash选择您感兴趣的字符串
  • 使用bash进行聚合

  • 嗨,Peter,谢谢你的查询,它让我了解了方向,但我还没有:)通过这个查询,我看到了重复字符串的总数。我想看到的是字符串和重复的数字:“foo”10次,“bar”100次,等等。。我试图输出集合的内容,但只得到奇怪的jscript异常。。你知道如何实现我想看到的吗?我真的很喜欢你的建议,因为它很好地解决了问题。然而,我希望你能理解,约翰·卡文因撰写oql而获得了赏金。我认为在某些情况下,理解oql是有用的。但是谢谢你!要做到这一点,请使用Open Query Browser->Java Basic->Group By Value。对于对象选择
    java.lang.String
    ,对于字段选择
    value
    。谢谢,这很好地解决了这个问题。oql在某种程度上难以使用。这一切都必须发生在一个函数中…哇,我不知道jvisualvm有那么强大。我发现一些字符串的计数值很高-您的代码是否排除垃圾(不是引用的字符串)?它使用“heap.objects”查找堆上的所有java.lang.String对象。没有排除非引用字符串的筛选。但是,根据堆转储的生成方式,JVM以前可能已经执行了完整的GC,在这种情况下,任何未引用的字符串都应该已经被删除,并且不包括在堆转储中。@JohanKaving我也尝试了OQL,但它只返回了一条类似“s”的记录