2011-11-23 9 views
12

既存のJavaソフトウェアのメモリ解析を行っています。同じ値であるが異なるインスタンスを持つオブジェクトの数を見るために、oqlにはsql 'group by'という同等のものがありますか?oqlによるJavaヒープ解析:ユニークな文字列を数えよう

SELECT COUNT(*) java.lang.Stringでの グループからs.toString(による)

私は重複の数と一緒に複製された文字列のリストを達成したいと思います。これは、String.intern()を使用して最適化できるように、大量のケースを表示することを目的としています。

例:

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

等...悲しいこと

答えて

19

ピーターDolbergによって回答に基づいているとVisualVM OQLコンソールで使用することができ、次の

それが作成または更新各文字列のすべての文字列のインスタンス上とのため map()コールを使用して起動
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; 
    } 
    } 
); 

配列countsのオブジェクトです。各オブジェクトはstringcountのフィールドを持ちます。

結果の配列には、文字列インスタンスごとに1つのエントリが含まれます。各エントリには、同じ文字列の前のエントリより1つ大きい値のcountが含まれます。 結果はcountフィールドでソートされ、その結果は次のようなものになります。

{ 
count = 1028.0, 
string = *null* 
} 

{ 
count = 1027.0, 
string = *null* 
} 

{ 
count = 1026.0, 
string = *null* 
} 

... 

を(私のテストで文字列"*null*"が最も一般的でした)。

最後のステップは、各文字列の最初の出現に対してtrueを返す関数を使用してこれをフィルタリングすることです。​​配列を使用して、どの文字列が既に含まれているかを追跡します。

+1

問題をうまく解決していただきありがとうございます。 oqlは何とか使いにくいです。それはすべて1つの機能で起こらなければならない... – paweloque

+0

うわー、それはjvisualvmが強力であることを知らなかった。私はいくつかの文字列のための高いカウント値を見つけました - あなたのコードはガベージ(参照文字列ではない)を除外しますか? – Jan

+1

"heap.objects"を使用して、ヒープ上のすべてのjava.lang.Stringオブジェクトを検索します。参照されていないStringを除外するフィルタリングはありません。しかし、ヒープ・ダンプがどのように生成されたかによって、JVMは完全なGCを前もって実行している可能性があります。その場合、参照されていないStringはすべて削除されていて、ヒープ・ダンプには含まれていません。 –

2

は、OQLで "でグループ" に相当するものはありません。私はあなたがjhatとVisualVMで使用されているOQLについて話していると仮定しています。

しかし、代わりがあります。 "select x from y"の構文の代わりに純粋なJavaScriptシンタックスを使用すると、操作するJavaScriptの能力が完全に発揮されます。

あなたが探している情報を得る別の方法は、単純ではありません。

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オブジェクトを模倣(重複なしでコレクション)セット:たとえば、ここにあなたのクエリと同じタスクを実行しますOQL「クエリ」です。マップ関数が各文字列を通過するとき、その文字列がすでに見えているかどうかを判断するためにこのセットが使用されます。重複は合計(戻り値0)にカウントされませんが、新しい文字列は返されます(戻り値1)。

+0

こんにちはピーター、クエリのおかげで、それは方向に私をもたらしますが、私はまだそこにいないよ:)このクエリでは、私は重複の合計数を確認文字列。私が見たいのは、文字列とリピート数です: 'foo'は10回、 'bar'は100回などです。セットの内容を出力しようとしましたが、奇妙なjscript例外を取得するだけですあなたが私が見たいものを達成する方法を知っていますか? – paweloque

7

代わりにEclipse Memory Analyzerを使用します。

+2

問題を非常にうまく解決するので、私はあなたの提案が本当に好きです。しかし、私は、賞金がoqlを書くためにJohan Kavingに行くことを理解することを願っています。私はoqlを理解することが有用な状況があるかもしれないと思います。しかし、感謝! – paweloque

+0

これを行うには、クエリブラウザを開く - > Javaの基礎 - >値でグループ化を使用します。オブジェクトの場合は 'java.lang.String'を選択し、フィールドの場合は' value'を選択します。 – kichik

0

私の解決策と経験を投稿するだけで、他の参考文献と同様の問題が起きることがあります。

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を返しました。これも多くの時間を無駄にしました)。

1

Aはるかに効率的なクエリ:

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'); 
関連する問題