Are anonymous listeners incompatible with weak ref

2019-03-18 02:58发布

问题:

I was reading this question that just got asked: Avoid memory leaks in callbacks?

And I was quite confused, until someone answered the following:

"The problem with this approach is you cannot have a listener which is only referenced in the collection as it will disappear randomly (on the next GC)"

Am I correct in my understanding that using a weak references, like when stored in a WeakHashMap, is incompatible with anonymous listeners?

I typically pass listeners like this:

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

}

And I keep track of the listeners using a CopyOnWriteArrayList (the default Observable above apparently uses an old Vector but its just an example to show how I typically create an anonymous class to use as a listener).

As a bonus question: when would the reference to the anonymous listener be eligible for GC should the observable subject use a WeakHashMap? When the main method exits? As soon as the obs.addObserver call is over?

I'm a bit confused about where/how/when references to anonymous class instances are kept/stored/elligible for GC.

Obviously if I'm keeping a normal reference it's not eligible for GC, but what when it's in a WeakHashMap, when does precisely the listener become elligible for GC?

回答1:

Yes, you are right, a listenable class maintaining the listeners with weak references (as does WeakHashMap) requires their independent persistence. Could be used for listener hierarchies where a listener has children and a parent.

For non-WeakReference usages an explicit removeListener must be called. Unless the listener object may live as long as the listenable object. In most use cases that is fine, and an anonymous class will do.

With anonymous class instances a leak (GC prevention) may only happen when accessing a final object outside the class body.

Note: WeakHashMap i.a. uses weak references for its own subclass of Map.Entry. Which may at times be quite mind boggling.



回答2:

If an object is only a key of a WeakHashMap, then it is eligible and likely to cleaned up on the next GC.

The whole idea of using a Weak referenced collection, is to implicitly remove listeners which are no longer referenced. (This avoid the potential for a memory leak) The problem is the listener can be removed prematurely and at a "random" point in time.