On Thu, 13 Oct 2022 22:17:09 GMT, Andy Goryachev <ango...@openjdk.org> wrote:

> Also, using your example above, it might be too easy to create a memory leak 
> by inadvertently referring to a long lived object:
> 
> ```
> getSkinnable().textProperty().when(active).addListener((src,prev,current) -> {
>   getSkinnable().setSomething(window.getSomething() + "..."); // window 
> reference makes the listener lambda uncollectable, resulting in a memory leak
> });
> ```

I'm not sure I follow your meaning.  Why would referring to `window` make the 
lambda uncollectable? The lambda is referring to `window`, not the other way 
around.

The current "alternative", which is weak listeners, is not what it is cracked 
up to be.  A weak listener that is not strongly referenced will be collected at 
a random time, including never, (almost) immediately or in 5 minutes.  All that 
time, the listener still functions, responds to potential events and property 
changes, even though the reason for its existence has since disappeared.

When a weak reference is collected depends on many things, including the chosen 
GC, its parameters, JDK versions, memory pressure, etc.  This proposal is 
specifically tailored to make the process of removing listeners deterministic 
without having to manually unregister listeners.  Weak listeners are completely 
unpredictable and could potentially live much longer than expected on certain 
GC's (or future improvements of GC's) that have different strategies for 
cleaning weak references.

A weak reference specifically is NOT something that gets cleaned up immediately 
upon the last reference disappearing. This can cause all kinds of phantom 
effects in JavaFX applications, if your listener does something like persisting 
state or printing something to the console. For example, a long lived model 
gets a weak listener attached to it when a dialog opens; the listener persists 
the last selected item.  The dialog is closed and reopened.  Now there might be 
two listeners, both persisting the last selected item. This may show up on your 
console as two database calls where one is expected.

You can argue this is bad programming and that those listeners should have been 
cleaned up specifically with a dispose method, and I agree, you get predictable 
behavior that way. And that's exactly what this proposal also brings, 
predictable behavior, using a syntax that doesn't require you to keep track of 
your listeners explicitely:

       
longLivedModel.indexProperty().when(dialog::shownProperty).addListener(persistPosition);

This detaches the listener immediately after the dialog is closed.  Not in 3 
seconds or 5 minutes, but as soon as it is no longer visible.  Opening a new 
dialog will not reinstate this listener. Reusing the same dialog however would, 
and it would start working again exactly as you'd expect as soon as the dialog 
is visible again.

-------------

PR: https://git.openjdk.org/jfx/pull/830

Reply via email to