TL;DR: GC is eating my active bindings.
I have an app that was developed and successfully deployed using JavaFX 2.2 on Java 7.
When I upgraded/transitioned to JavaFX 8.0 (and Java 8), certain features would "mysteriously" stop working--mid application lifecycle--with no exceptions or other indications of erroneous state change. For example; buttons stop working, custom cell renderers stopped being applied, enabled/disabled state stopped getting updated.
After many hours of digging, I think I've tracked the problem down to what I understand to be some changes in JavaFX 8 and internal usage of javafx.beans.WeakListener
to deal with memory leaks found in JavaFX 2.2. Basically, it seems that the bindings that I'm creating to manage data state dependency are getting garbage collected despite the fact that the Node
s they control are still active.
The problems most often seem to arise when I instantiate bindings using anonymous classes. Some but not all of my problems can be fixed by storing a reference to the binding as a class member, thereby keeping the GC from collecting it. I've even had whole controllers get GC'd because they were instantiated via FXML loading and never directly referenced (I now always stuff a reference to the controller in the parent node's userData
property).
My problems are:
- associated bugs arise non-deterministically (or are at least a function of memory footprint).
- if bindings through anonymous classes should be avoided, it's a lot of work to find every instance in a large, existing code base to change it.
- even if I could find every instance, it clutters up the code immensely.
Frustratingly, I can't seem to find anything in the Oracle documentation that says "don't create bindings with anonymous classes", or any other guidelines for ensuring reliable use of bindings. A lot of the code examples out there use anonymous class bindings. Nor can I find any notes on how to properly update a JavaFX 2.2 app to JavaFX 8.
Any advice from people developing non-trivial JavaFX apps is greatly appreciated (I've been developing JavaFX 2.x apps for 3 years, and Swing apps for > 15 years, so this isn't exactly a n00b question).
Note: My question is similar to Clean JavaFX property listeners and bindings (memory leaks), but I want to know specifically and definitively how to use complex bindings and ensure they won't be garbage collected at random times, without resorting to polluting classes with references to every instance.