Pros and Cons of Listeners as WeakReferences

前端 未结 12 995
天命终不由人
天命终不由人 2020-12-04 12:18

What are the pros and cons of keeping listeners as WeakReferences.

The big \'Pro\' of course is that:

Adding a listener as a WeakReference means the listener

相关标签:
12条回答
  • 2020-12-04 12:19

    I can't think of any legitimate use case for using WeakReferences for listeners, unless somehow your use case involves listeners that explicitly shouldn't exist after the next GC cycle (that use case, of course, would be VM/platform specific).

    It's possible to envision a slightly more legitimate use case for SoftReferences, where the listeners are optional, but take up a lot of heap and should be the first to go when free heap size starts getting dicey. Some sort of optional caching or other type of assisting listener, I suppose, could be a candidate. Even then it seems like you'd want the internals of the listeners to utilize the SoftReferences, not the link between the listener and listenee.

    Generally if you're using a persistent listener pattern, though, the listeners are non-optional, so asking this question may be a symptom that you need to reconsider your architecture.

    Is this an academic question, or do you have a practical situation you're trying to address? If it's a practical situation I'd love to hear what it is -- and you could probably get more, less abstract advice on how to solve it.

    0 讨论(0)
  • 2020-12-04 12:20

    I have seen tons of code where listeners were not unregistered properly. This means they were still called unnecessarily to perform unnecessary tasks.

    If only one class is relying on a listener, then it is easy to clean, but what happens when 25 classes rely on it? It becomes much trickier to unregister them properly. The fact is, your code can start with one object referencing your listener and end up in a future version with 25 objects referencing that same listener.

    Not using WeakReference is equivalent to taking a big risk of consuming unnecessary memory and CPU. It is more complicated, trickier and requires more work with hard references in the complex code.

    WeakReferences are full of pros, because they are cleaned up automatically. The only con is that you must not forget to keep a hard reference elsewhere in your code. Typically, that would in objects relying on this listener.

    I hate code creating anonymous class instances of listeners (as mentioned by Kirk Woll), because once registered, you can't unregister these listeners anymore. You don't have a reference to them. It is really bad coding IMHO.

    You can also null a reference to a listener when you don't need it anymore. You don't need to worry about it anymore.

    0 讨论(0)
  • 2020-12-04 12:29

    To be honest I don't really buy that idea and exactly what you expect to do with a addWeakListener. Maybe it is just me, but it appear to be a wrong good idea. At first it is seducing but the problems it might implies are not negligible.

    With weakReference you are not sure that the listener will no longer be called when the listener itself is no longer referenced. The garbage collector can free up menmory a few ms later or never. This mean that it might continue to consume CPU and make strange this like throwing exception because the listener shall not be called.

    An example with swing would be to try to do things you can only do if your UI component is actually attached to an active window. This could throw an exception, and affect the notifier making it to crash and preventing valid listeners to be notofied.

    Second problem as already stated is anonymous listener, they could be freed too soon never notified at all or only a few times.

    What you are trying to achieve is dangerous as you cannot control anymore when you stop receiving notifications. They may last for ever or stop too soon.

    0 讨论(0)
  • 2020-12-04 12:29

    In my opinion it's a good idea in most cases. The code that is responsible for releasing the listener is at the same place where it gets registered.

    In practice i see a lot of software which is keeping listeners forever. Often programmers are not even aware that they should unregister them.

    It usually is possible to return a custom object with a reference to the listener that allows manipulation of when to unregister. For example:

    listeners.on("change", new Runnable() {
      public void run() {
        System.out.println("hello!");
      }
    }).keepFor(someInstance).keepFor(otherInstance);
    

    this code would register the listener, return an object that encapsulates the listener and has a method, keepFor that adds the listener to a static weakHashMap with the instance parameter as the key. That would guarantee that the listener is registered at least as long as someInstance and otherInstance are not garbage collected.

    There can be other methods like keepForever() or keepUntilCalled(5) or keepUntil(DateTime.now().plusSeconds(5)) or unregisterNow().

    Default can be keep forever (until unregistered).

    This could also be implemented without weak references but phantom references that trigger the removal of the listener.

    edit: created a small lib which implements a basic version of this aproach https://github.com/creichlin/struwwel

    0 讨论(0)
  • 2020-12-04 12:29

    I have 3 suggestions for the original poster. Sorry for resurrecting an old thread but I think my solutions were not previously discussed in this thread.

    First, Consider following the example of javafx.beans.values.WeakChangeListener in the JavaFX libraries.

    Second, I one upped the JavaFX pattern by modifying the addListener methods of my Observable. The new addListener() method now creates instances of the corresponding WeakXxxListener classes for me.

    The "fire event" method was easily modified to dereference the XxxWeakListeners and to remove them when the WeakReference.get() returned null.

    The remove method was now a bit nastier since I need to iterate the entire list, and that means I need to do synchronization.

    Third, Prior to implementing this strategy I employed a different method which you may find useful. The (hard reference) listeners got a new event they did a reality check of whether or not they were still being used. If not, then they unsubscribed from the observer which allowed them to be GCed. For short lived Listeners subscribed to long lived Observables, detecting obsolescence was fairly easy.

    In deference to the folks who stipulated that it was "good programming practice to always unsubscribe your listeners, whenever a Listener resorted to unsubscribing itself, I made sure to create a log entry and corrected the problem in my code later.

    0 讨论(0)
  • 2020-12-04 12:34

    WeakListeners are useful in situations where you specifically want GC to control the lifetime of the listener.

    As stated before, this really is different semantics, compared to the usual addListener/removeListener case, but it is valid in some scenarios.

    For example, consider a very large tree, which is sparse - some levels of nodes are not explicitly defined, but can be inferred from parent nodes further up the hierarchy. The implicitly defined nodes listen to those parent nodes that are defined so they keep their implied/inherited value up to date. But, the tree is huge - we don't want implied nodes to be around forever - just as long as they are used by the calling code, plus perhaps a LRU cache of a few seconds to avoid churning the same values over and over.

    Here, the weak listener makes it possible for child nodes to listen to parents while also having their lifetime decided by reachability/caching so the structure doesn't maintain all the implied nodes in memory.

    0 讨论(0)
提交回复
热议问题