On 8/14/2026 5:45 PM, Dan Smith wrote:
On Aug 14, 2026, at 12:58 PM, Kevin Rushforth <[email protected]> 
wrote:

On 8/6/2026 2:52 PM, Kevin Rushforth wrote:
On 8/6/2026 1:33 PM, Dan Smith wrote:
On Aug 3, 2026, at 8:34 AM, Kevin Rushforth <[email protected]> wrote:

First, some JavaFX UI controls APIs take a list of objects. JavaFX internally 
creates a WeakReference to an individual object in some cases. This is tracked 
by JDK-8387301 [2].
I was curious about the use cases, and how they might react to different 
reference-clearing policies, so I dug into the code.

For TablePosition (#2 in JDK-8387301), turns out the WeakReference seems to go 
unused: I can delete the private `itemRef` field and the package-access 
`getItem` method, and everything still builds fine*.

(*Caveat that this is a complicated system, I’ve only built on macOS and 
haven’t run any tests. Any reason to believe this is a platform-specific 
dependency?)

I’ll keep looking at the other cases, see if they can provide any insight into 
reference-clearing policies...
Thanks for looking into this. I know we don't rely on any reference clearing 
behavior, but I haven't dug into how we are using those WeakReferences in UI controls 
or whether we still need them at all (unlike the WebView Java <--> JS bridge 
case where I know how and why we are using them). It would be interesting to dig 
deeper to see if they are needed at all for controls.
The private itemRef in TablePosition that you pointed out is indeed unused and 
can be removed. The other three are still needed.

We don't rely on reference clearing behavior, so a simple wrapper will suffice 
for our needs.

Although... we do care about not introducing memory leaks.

I’ve been playing around with SelectedItemsReadOnlyObservableList, again with 
the goal of finding a use case that could inform our design choices.

Here, I’m stuck trying to find a scenario where the WeakReference could get 
cleared:

The idea is that there’s a list of indices of selected items in an 
ObservableList, and another list that acts as a view of the subset of 
ObservableList items that are selected. The subset view keeps around a cache of 
last-seen selected items so that it can create a “removed” change event that 
shares the no-longer-selected item with listeners.

There’s some worry that the cache of last-seen selected items will cause a 
memory leak, so they are wrapped in WeakReferences. But… if they’re still in 
the underlying list, they won’t be GC’ed. And when I remove them from the list, 
the selection always seems to be auto-updated to a new, non-GC'ed selection, 
without creating any change events referencing the removed object.

If there *were* a way to trigger a change event referring to an object that had 
been GC’ed, then the removal change event would reference ’null’, which would 
be a different problem.

Agreed. This seems odd and worth a follow-up. The current design doesn't seem robust. If the weak reference were ever reclaimed before the change removal notification was delivered, reporting "null" as a removed item would likely cause problems (e.g., confuse applications that are not expecting a null item).

The case of oldRowItemRef in TableCell and TreeTableCell are a more typical "cache the last thing seen" and are used as an optimization, but even those should be reexamined.

(I experimented with some exotic ObservableLists that have unstable 
results—e.g., each read allocates a new object—and then all sorts of weird 
things happen, but this seems outside the intended scope of the API.)

As this relates to value objects:

- If memory leaks are a problem for identity objects, wouldn’t they also be a 
problem for value objects (which might, e.g., reference a large array)? Which 
would call for immediately discarding the value objects—but if that works, why 
have a cache at all?

- If nulls in removal change events are the problem we need to avoid for value 
objects, then that calls for never releasing the value objects. But wouldn’t 
that also be a problem for identity objects? In that case, WeakReferences seem 
like the wrong solution, and the cache should just hold direct references to 
everything.

That's an interesting question. And one I'll need to drill into when I get to the WebView Java <--> JS bridge implementation. Up until now, I've been assuming that we don't care much about whether value objects leak. For small objects like the boxed primitive classes, that seems a reasonable assumption (what does it mean to "leak" an integer?). However, if a user-defined value object (e.g., a simple value record) contains a large array of integers or a reference to a user-defined identity object, then I think we do care. In that case, the solution that I'm proposing could lead to memory leaks in the case of user-defined value objects.

For example, if the application creates the following record:

    value record Container(Integer[] indices);

    Container container = new Container(indices);
    jsObject.setMember("myContainer")

The updated native JS bridge code will create a JGlobalRef (instead of a JWeakGlobalRef), since the parameter is a value object, which will leak.

Do I understand this correctly? If so, then we might need to rethink this.

-- Kevin

Reply via email to