I have realized that my project uses a lot of JavaFX ChangeListeners
to keep track of certain conditions.
I am pretty sure that listeners do not get garbage collected when used with property.addListener(ChangeListener)
, but if I put my listeners in lambda form instead of declaring them first, will they still not get garbage collected?
Example:
field.focusedProperty().addListener((obs, oldVal, newVal) -> {
// Do stuff
}
});
On a side note, do all the listeners get cleared when I close the program or do they continue to persist?
A listener you register with an observable will not be garbage collected so long as it is registered with the observable. Assuming, of course, there's a strong reference to the observable. This is because the observable keeps a strong reference to each listener registered with it. In fact, this can be the cause of memory leaks in your application if you're not careful. That's why we have:
To make your application more resistant to memory leaks you can use implementations of WeakListener
. There are five public implementations provided for you:
WeakInvalidationListener
WeakChangeListener
WeakListChangeListener
WeakSetChangeListener
WeakMapChangeListener
These implementations wrap their corresponding listener and hold it in a WeakReference
. That way the observable only has a strong reference to the weak listener and not the "real" listener. And that's why you have to keep a strong reference to the "real" listener yourself for as long as its needed, otherwise it will be garbage collected too soon.
Here's an example of using a weak listener:
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.scene.Node;
public class Foo {
// strong reference to "real" listener
private final ChangeListener<Boolean> focusListener =
(obs, oldVal, newVal) -> {
// do something...
};
private final Node node;
public Foo(Node node) {
this.node = node;
node.focusedProperty().addListener(new WeakChangeListener<>(focusListener));
}
}
If you need to be able to remove the weak listener at will then you'll need to keep a reference to it as well.
You should use a weak listener when you can't guarantee the listener will be removed when no longer needed. This is especially important if the listener captures a reference to other objects (e.g. the Foo
instance in the above example).
Don't bother using a weak listener if the observable and listener are guaranteed to be garbage collected at relatively the same time. For example, if Foo
had a property and adds a listener to said property itself (e.g. this.someProperty().addListener((...) -> {...})
) then the property, and thus the listener, will be garbage collected when the Foo
instance is garbage collected.
Also, using weak listeners may be more effort than they're worth if:
If unsure, you can always go the non-weak route to start and only change to weak listeners if you profile a problem.
Everything described here works the same for EventHandler
and WeakEventHandler
. Just note that the latter does not implement WeakListener
.
Does using a lambda expression to implement a listener (or handler) change anything? Not in any way relevant to this context. A lambda expression is simply an implementation of a functional interface. An instance created via a lambda expression is just an instance like any other.
All memory allocated to the process is released back to the operating system when said process exits. That means all objects cease to exist in memory.