2013-06-05 9 views
5

私のアプリケーションは、特定のオブジェクトの使用状況を記録します。私のセットアップはAspectJを使用して、興味のあるコンテキストを識別し、これらの用途を記録します。後で分析のためにログファイルをロードしますが、効率的な理由から、オブジェクトがもはや到達可能でないときを知ることは有用です。オブジェクトがガベージコレクトされたときのロギング

私の現在のアプローチは、私が興味を持っているオブジェクトを「ガベージ・ロガー」で記録することです。このガベージ・ロガーは、オブジェクトのIDハッシュコードを含む「保護者」オブジェクトを作成し、弱いハッシュマップに格納します。アイデアは、オブジェクトが収集されると、弱いハッシュマップからセーバーオブジェクトが削除されて収集されるため、収集されたオブジェクトのアイデンティティハッシュコードを記録するコードを実行するということです。ガベージコレクタでボトルネックを起こさないように、別のスレッドとキューを使用します。ここではごみロガーのコードは次のとおりです。

public class GarbageLogger extends Thread { 

    private final Map<Object,Saver> Savings = 
     Collections.synchronizedMap(new WeakIdentityHashMap<Object,Saver>()); 
    private final ConcurrentLinkedQueue<Integer> clearTheseHash = 
     new ConcurrentLinkedQueue<Integer>(); 

    public void register(Object o){ 
     Savings.put(o,new Saver(System.identityHashCode(o)); 
    } 

    private class Saver{ 
     public Saver(int hash){ this.hash=hash;} 
     private final int hash; 
     @Override 
     public void finalize(){ 
      clearTheseHash.add(hash); 
     } 
    } 

    @Override 
    public void run(){ 

     while(running){   
      if((clearTheseHash.peek() !=null)){ 
       int h = clearTheseHash.poll(); 
       log(h); 
      } 
      else sleep(100); 
     } 
    } 

    // logging and start/end code omitted 
} 

私の問題はスペースが必要とされない限り、弱いハッシュマップは、必ずしもそのエントリをクリアしないので、これはオブジェクトがされた後、私は長い時間を待っているかもしれませんが、非常に複雑なようで、ということですそれを記録する前に収集されます。基本的に、私はこれを達成するためのより良い方法を探しています。

注 - 私は任意のオブジェクトを監視しており、作成を制御できないため、finalizeメソッドをオーバーライドできません。

+0

本当に欲しいものは[参照キュー](http://stackoverflow.com/a/14450693/869736)です。 –

+0

私はWeakIdentityHashMapとConcurrentLinkedQueueをReferenceQueueに置き換えますが、収集された参照をポップしてログに記録するにはGarbageLoggerスレッドがまだ必要でしょうか? – selig

+0

これは正しいです。 –

答えて

6

ガベージコレクションイベントに応答する従来の方法は、彼らが参照されるオブジェクトがGC'dあるときに自動的にエンキューされます、その後、定期的にReferenceQueue(おそらく中をポーリングするにReferenceQueue、とWeakReference Sを登録することです別のスレッド)を使用してクリーンアップを実行します。クリーンアップが発生し、その情報を得るためにあなたのMyWeakReferenceに戻っReferenceQueueWeakReferenceオブジェクトをキャストする際

A標準トリックは、あなたが知りたい任意の追加情報を付加する、WeakReferenceクラスを拡張することです。

3

迅速な結果を与えるかもしれない、やや単純な選択肢を(ともSavings上の潜在的なボトルネックを緩和すること)

private final ConcurrentMap<WeakReference, Integer> savings = new ConcurrentHashMap<>(); 

public void run() { 
    while(running) { 
     for(WeakReference reference : savings.keySet()) { 
      if(reference.get() == null) { 
       log(savings.remove(reference)); 
      } 
     } 
     sleep(1000); 
    } 
} 

欠点は、あなたが継続的にクリアの参照を見つけるためにマップを反復処理しなければならないということです、利点はより簡単な実装であり、reference.get() == nullは、オブジェクトがクリアされるとすぐに真となります(ただし、WeakHashMapにクリアされたオブジェクトの登録に遅延が生じることがあります)。 ConcurrentMapを使用すると、Collections.synchronizedMapの使用によって作成されるボトルネックが緩和され、さらに重要なことに、for-eachループがConcurrentModificationExceptionを投げるのを防ぐことができます。

+0

はい、シンクロナイズドマップ上のボトルネックがおそらく問題になります。参照キューを持つ上記のコメント(コメント内の)解決策もボトルネックになると思いますか?...私はそれを追加する際に同期する必要があると思います。 – selig

+0

+1はボトルネックの問題を強調します。 – selig

+1

@selig参照キューにボトルネックはありません。 [This code](http://java.dzone.com/articles/letting-garbage-collector-do-c)はあなたを助けてくれるかもしれません - 参照キューと同時マップ –

関連する問題