2013-06-05 3 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

Итак, я бы заменил WeakIdentityHashMap и ConcurrentLinkedQueue на ReferenceQueue, но все равно нужен поток GarbageLogger для сбора собранных ссылок и их регистрации? – selig

+0

Это правильно. –

ответ

6

Традиционный способ реагировать на события сбора мусора зарегистрировать WeakReference сек с ReferenceQueue, в котором они будут автоматически помещён, когда объект ссылки является GC'd, а затем периодически опрашивать ReferenceQueue (возможно, отдельный поток) для очистки.

Стандартная Хитрость заключается в том, чтобы расширить WeakReference класс, придавая любую дополнительную информацию, которую вы хотите знать, когда происходит очистка, а затем бросила WeakReference объектов в ReferenceQueue назад к Вашим MyWeakReference, чтобы получить информацию.

3

An несколько более простой вариант, который может дать более быстрые результаты (а также уменьшает потенциальное узкое место на 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, и, что более важно, предотвращает выброс каждого цикла из ConcurrentModificationException.

+0

Да, узкое место на синхронизированной карте, вероятно, будет проблемой. Вы думаете, что вышеупомянутое решение (в комментарии) с ссылочной очередью также было бы узким местом? ... Я предположил, что мне придется синхронизировать с добавлением к этому. – selig

+0

+1 для освещения проблемы с узким местом. – selig

+1

@selig Очередь ссылок не стала бы узким местом. [Этот код] (http://java.dzone.com/articles/letting-garbage-collector-do-c) может помочь вам - он объединяет ссылочную очередь с параллельной картой –

Смежные вопросы