Search code examples
javaevent-handlingweak-references

Why I need to find an object with exactly the same lifecycle with the listerner object when using a weak reference?


I'm reading reading some old articles written by Brian Goetz in 2005 avaliable on IBM developerWorks. One of them confused me.

In this article on how to design good event models, he talked about the potential of memory leaks on bad listener uses. Here, I noticed he mentioned that if I want to store a lisenter with a weak reference, I will have to find an object with the same lifecycle as the listener object.

One approach that is sometimes suggested for dealing with lapsed listeners(*) is to use weak references. While this approach is possible, it's fairly tricky to implement. For it to work, you need to find another object whose lifecycle is exactly the lifecycle of your listener and arrange for it to hold the strong reference to your listener, which is not always easy.

* Note: lapsed listeners are listeners that are no longer used by didn't get themselves unregistered.

This is weird. Isn't a WeakHashMap good enough? If not, why? Or is that WeakHashMap just the "object" I need? That doesn't seems tricky at all...

I've also noticed that the article comes from 2005. If it's solely a legacy issue, when did the change take place? I think I need to know it as I may eventually be dealing with older JDKs.


Solution

  • The problem is that if you keep a strong reference to a listener (or, for that matter, anything) too long, it will outlive its usefulness. (In the example code in the article he shows a case where a listener is registered, then time passes, then the listener is unregistered. But if there's an exception thrown in between, the listener stays registered past its time. Don't do that.) If OTOH you rely on weak references, but drop all strong references too soon, the listener could be collected before its time. The solution is to hold strong references just long enough. That's what he means by storing that reference in an object with the same "lifecycle".

    You can keep your Map from holding the reference too long by using a WeakHashMap. That solves the holding it too long problem*, but that still leaves you open to losing the listener prematurely. So he wants you to put a strong reference to the listener inside something else that already lives just long enough.

    That's easier said than done, which is why he says it is "tricky to implement".

    *It solves the holding it too long problem in part. The issue is that GC isn't guaranteed to run in a timely manner, or indeed ever. So even with weak references you may end up with a listener that is lapsed.