2013-06-05 11 views
5

Moja aplikacja rejestruje użycie pewnych obiektów - moja konfiguracja używa AspectJ do identyfikacji kontekstów, które mnie interesują i rejestruje te zwyczaje. Później ładuję pliki dzienników do analizy, ale ze względów wydajnościowych warto wiedzieć, kiedy obiekt nie jest już dostępny.Rejestrowanie, gdy obiekty są śmieciami zebrane

Moje obecne podejście polega na rejestrowaniu obiektów, które mnie interesują, za pomocą "rejestrującego śmieci", który następnie tworzy obiekt "oszczędzający", zawierający kod skrótu tożsamości obiektu i przechowuje go na słabej mapie skrótów. Chodzi o to, że gdy obiekt zostanie zebrany, obiekt wygaszacza zostanie usunięty ze słabej mapy skrótu i ​​zebrany, w ten sposób uruchamiając kod, aby zarejestrować kod skrótu tożsamości zgromadzonego obiektu. Używam osobnego wątku i kolejki, aby zapobiec pojawieniu się wąskiego gardła w koszu na śmieci. Oto kod śmieci rejestrator:

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 
} 

Moim problemem jest to, że wydaje się to bardzo zawiłe, a ponieważ słaby hash mapa nie będzie koniecznie usunąć swoje wpisy, chyba że pamięć jest potrzebna, to może czekać długo po obiekt jest zebrane przed nagraniem. Zasadniczo szukam lepszego sposobu, aby to osiągnąć.

Uwaga - Monitoruję dowolne obiekty i nie kontroluję ich tworzenia, więc nie można przesłonić ich metod zakończenia.

+0

Wygląda na to, że naprawdę chcesz [kolejka referencyjna] (http://stackoverflow.com/a/14450693/869736). –

+0

Chciałbym zastąpić WeakIdentityHashMap i ConcurrentLinkedQueue z ReferenceQueue, ale nadal potrzebował wątek GarbageLogger, aby pobrać zebrane referencje i zarejestrować je? – selig

+0

Zgadza się. –

Odpowiedz

6

Tradycyjny sposób reagować na zdarzenia zbiórki śmieci jest zarejestrowanie WeakReference s z ReferenceQueue, w którym będą one automatycznie skolejkowany gdy odwołuje obiekt jest GC'd, a następnie okresowo odpytywać ReferenceQueue (ewentualnie w oddzielny wątek) do czyszczenia.

Standardowa Sztuką jest rozszerzenie klasy WeakReference, załączając wszelkie dodatkowe informacje, które chcesz wiedzieć, kiedy nastąpi czyszczenie, a następnie do oddania WeakReference obiektów w ReferenceQueue powrotem do MyWeakReference, aby uzyskać informacje.

3

An nieco prostszą alternatywę, która może dać szybsze rezultaty (a także łagodzi potencjalne wąskie gardło na Savings) jest

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

Minusem jest to, że trzeba nieustannie iterację mapie, aby wybrać wyczyszczone referencje ale zaletą jest prostsza implementacja, a reference.get() == null będzie prawdą, gdy tylko obiekt zostanie wyczyszczony (podczas gdy może wystąpić opóźnienie w zarejestrowaniu wyczyszczonego obiektu w WeakHashMap). Korzystanie z funkcji ConcurrentMap zmniejsza wąskie gardło, które może powstać w wyniku korzystania z urządzenia Collections.synchronizedMap, a co ważniejsze zapobiega wysyłaniu przez pętlę for a ConcurrentModificationException.

+0

Tak, wąskim gardłem na zsynchronizowanej mapie prawdopodobnie byłby problem. Czy uważasz, że powyższe rozwiązanie (w komentarzu) z kolejką referencyjną również byłoby wąskim gardłem? ... Przypuszczałem, że będę musiał zsynchronizować się przy dodawaniu do tego. – selig

+0

+1 za wyróżnienie problemu wąskich gardeł. – selig

+1

@selig Kolejka referencyjna nie stanowi wąskiego gardła. [Ten kod] (http://java.dzone.com/articles/letting-garbage-collector-do-c) może ci pomóc - łączy kolejkę referencyjną z współbieżną mapą –

Powiązane problemy