2013-06-05 8 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으로 WeakReference의를 등록하고 정기적으로 ReferenceQueue를 폴링하는 것입니다 별도의 스레드)를 사용하여 정리합니다. 정리가 발생하고 정보를 얻을 수 있도록 MyWeakReference에 다시 ReferenceQueue에서 WeakReference 개체를 캐스팅 할 때

표준 트릭은 당신이 알아야 할 추가 정보를 첨부의 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은 객체가 지워지는 즉시 true가됩니다 (반면 WeakHashMap에 지워진 객체를 등록하는 데 지연이있을 수 있음). ConcurrentMap을 사용하면 Collections.synchronizedMap을 사용하여 생성 될 수있는 병목 현상이 완화되고 for-each 루프가 ConcurrentModificationException이되지 않도록 방지 할 수 있습니다.

+0

예 동기화 된지도의 병목 현상이 문제 일 수 있습니다. 참조 대기열이있는 위의 해결 방법 (의견에서)이 병목 현상이 될 것이라고 생각하십니까? ... 내가 추가 할 때 동기화해야한다고 생각합니다. – selig

+0

+1 병목 현상 문제 강조 표시. – selig

+1

@selig 참조 대기열에 병목 현상이 나타나지 않습니다. [이 코드] (http://java.dzone.com/articles/letting-garbage-collector-do-c)가 도움이 될 수 있습니다. 참조 대기열을 동시지도와 결합합니다. –