2013-06-05 54 views
5

我的應用程序記錄了某些對象的用法 - 我的設置使用AspectJ來識別我感興趣的上下文並記錄這些用法。我稍後加載日誌文件進行分析,但出於效率的原因,知道何時不再可訪問對象很有用。當對象被垃圾收集時記錄日誌

我目前的做法是用「垃圾記錄器」記錄我感興趣的對象,然後創建一個包含對象身份哈希碼的'保存器'對象,並將其存儲在弱哈希映射中。這個想法是當收集對象時,保存對象將從弱哈希映射中移除並收集,從而運行代碼以記錄收集對象的身份哈希代碼。我使用單獨的線程和隊列來防止在垃圾回收器中造成瓶頸。這裏的垃圾記錄代碼:

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 
} 

我的問題是,這似乎很令人費解,而且因爲除非需要空間弱哈希映射不一定會清除其條目,我可能會等待很長一段時間之後的對象是在錄製之前收集。基本上,我正在尋找更好的方法來實現這一目標。

注 - 我正在監視任意對象,並且無法控制其創建,因此無法覆蓋它們的最終化方法。

+0

這聽起來像你真正想要的是[參考隊列](http://stackoverflow.com/a/14450693/869736)。 –

+0

所以我會用ReferenceQueue替換WeakIdentityHashMap和ConcurrentLinkedQueue,但是仍然需要GarbageLogger線程來彈出收集的引用並記錄它們? – selig

+0

這是正確的。 –

回答

6

的傳統方式向垃圾收集響應事件是一個ReferenceQueue註冊WeakReference S,其會自動將排隊時引用的對象GC'd,然後定期輪詢ReferenceQueue(可能在一個單獨的線程)來執行清理。

標準的訣竅是延長WeakReference類,附加你想知道的任何其他信息時,清理時,然後在ReferenceQueueWeakReference對象投射到你的MyWeakReference來獲取信息。

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); 
    } 
} 

的缺點是,你必須通過地圖,以便找到清理引用不斷迭代,但優點是更簡單的實現,並且只要對象被清除(而在WeakHashMap中註冊已清除的對象可能存在延遲),則reference.get() == null將爲真。使用ConcurrentMap可以減輕您使用Collections.synchronizedMap時可能產生的瓶頸,更重要的是可以防止for-each循環投擲ConcurrentModificationException

+0

是的,同步映射上的瓶頸可能是一個問題。你認爲上面的解決方案(在評論中)帶有參考隊列也會是一個瓶頸?...我想我必須同步添加。 – selig

+0

+1突出瓶頸問題。 – selig

+1

@selig參考隊列不會出現瓶頸。 [此代碼](http://java.dzone.com/articles/letting-garbage-collector-do-c)可能會幫助您 - 它將參考隊列與併發映射 –