Анонимные слушатели несовместимы со слабыми ссылками?
Я читал этот вопрос, который только что спросил: Избегайте утечек памяти в обратных вызовах?
И я был очень смущен, пока кто-то не ответил на следующее:
"Проблема с этим подходом заключается в том, что у вас не может быть слушателя, который упоминается только в коллекции, поскольку он случайно исчезнет (на следующем GC)"
Я правильно понимаю, что использование слабых ссылок, например, когда они хранятся в файле WeakHashMap, несовместимо с анонимными слушателями?
Я обычно передаю слушателям вот так:
public static void main(String[] args) {
final Observable obs = new SomeObservable();
obs.addObserver(new Observer() {
public void update(final Observable o, final Object arg) {
System.out.println("Notified");
}
});
obs.notifyObservers();
... // program continues its life here
}
private static final class SomeObservable extends Observable {
@Override
public void addObserver(final Observer o) {
super.addObserver(o);
setChanged(); // shouldn't be done from here (unrelated to the question)
}
}
И я отслеживаю слушателей с помощью CopyOnWriteArrayList (по умолчанию Observable, очевидно, использует старый вектор, но это просто пример, показывающий, как я обычно создаю анонимный класс для использования в качестве слушателя).
В качестве бонусного вопроса: когда ссылка на анонимного слушателя будет иметь право на GC, если наблюдаемый субъект использует WeakHashMap? Когда основной метод выходит? Как только вызов obs.addObserver закончился?
Я немного смущен тем, где/как/когда ссылки на экземпляры анонимного класса хранятся/сохраняются/доступны для GC.
Очевидно, что если я поддерживаю нормальную ссылку, он не подходит для GC, но что, когда он в WeakHashMap, когда именно слушатель становится понятным для GC?
Ответы
Ответ 1
Да, вы правы, слушающий класс, поддерживающий слушателей со слабыми ссылками (как и WeakHashMap), требует их независимого сохранения. Может использоваться для иерархии слушателей, где слушатель имеет дочерние элементы и родительский элемент.
При использовании не-WeakReference необходимо вызывать явный removeListener. Если объект прослушивателя не может прожить до тех пор, пока его прослушиваемый объект. В большинстве случаев это нормально, и анонимный класс будет делать.
С анонимными экземплярами класса утечка (предотвращение GC) может произойти только при доступе к окончательному объекту вне тела класса.
Примечание: WeakHashMap i.a. использует слабые ссылки для собственного подкласса Map.Entry. Который иногда может быть совершенно ошеломляющим.
Ответ 2
Если объект является только ключом WeakHashMap, то он имеет право и может быть очищен на следующем GC.
Вся идея использования коллекции с слабыми ссылками - это неявно удалить прослушиватели, на которые больше не ссылаются. (Это позволяет избежать утечки памяти). Проблема заключается в том, что слушатель может быть удален преждевременно и в "случайный" момент времени.