匿名侦听器是否与弱引用不兼容?

我正在阅读这个问题,刚刚被问到:避免回调中的内存泄漏?

我很困惑,直到有人回答以下问题:

“这种方法的问题在于,你不能有一个只在集合中引用的侦听器,因为它会随机消失(在下一个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跟踪侦听器(上面的默认可观察显然使用旧的Vector,但它只是一个例子,以展示我通常如何创建一个匿名类作为侦听器)。

作为一个额外的问题:如果可观察的主题使用WeakHashMap,那么对匿名听众的引用何时有资格获得GC?当 main 方法退出时?一旦obs.addObserver调用结束?

我对GC保存/存储/可识别对匿名类实例的引用的位置/方式/时间有点困惑。

显然,如果我保留一个正常的引用,它就不符合GC的条件,但是当它在WeakHashMap中时,听者什么时候才能获得GC?


答案 1

是的,你是对的,一个可听的类维护具有弱引用的侦听器(就像WeakHashMap一样)需要它们独立的持久性。可用于侦听器层次结构,其中侦听器具有子级和父级。

对于非弱引用用法,必须调用显式 removeListener。除非侦听器对象的生存时间可能与可侦听对象一样长。在大多数用例中,这很好,匿名类就可以了。

对于匿名类实例,只有在访问类体外部的最终对象时,才会发生泄漏(GC 预防)。

注意:WeakHashMap 即对其自己的 Map.Entry 子类使用弱引用。这有时可能令人难以置信。


答案 2

如果一个对象只是 WeakHashMap 的一个键,那么它就有资格并且很可能在下一个 GC 上清理。

使用弱引用集合的整个想法是隐式删除不再引用的侦听器。(这避免了内存泄漏的可能性)问题是监听器可以过早地在“随机”时间点被删除。


推荐