On Fri, 12 Mar 2021 15:32:10 GMT, Florian Kirmaier <fkirma...@openjdk.org> 
wrote:

>> I think others can review this. I do have a couple questions:
>> 1. In general, I don't like the idea of just making everything a weak 
>> reference, since it often masks a design issue. Two exceptions are for 
>> caches and for back references to a "parent" or controlling object that has 
>> a strong reference to "this" object (most of our weak listeners fall into 
>> this latter pattern). It sounds like latter case also applies here. Can you 
>> confirm that?
>> 2. Have you verified that all the places that use the fields that are now 
>> WeakReferences are prepared to deal with `get()` returning a null object?
>
> About whether we should use WeakReference here or not. 
> 
> It definitely falls into the exception for referring to the Parrent of a 
> Node. (Or to the Parent in a more abstract sense, I think it can also be the 
> parent of the parent, or even from another SceneGraph.)
> 
> I don't know the CSS code very well, so I currently don't have the knowledge 
> how to change it.
> But if we would change this variable, whenever the node is removed from the 
> SceneGraph, my concern would be that it would have an unfavorable complexity. 
> Currently (I hope) the complexity of removing a Node from the SceneGraph is 
> O(1). If we would remove the stylehelper from the node, then the complexity 
> would be O(<nodes-in-the-tree>).
> 
> The current change assumes that we don't process the CSS, when a node is 
> removed from the SG. This is why it isn't checked for null. I would argue, if 
> this causes an Error, then it just reveals another issue, which would be 
> preferable over a more complicated fix, and also changing the complexity of 
> removing nodes from the SG.

Below is a fix that I tried, It fixes the issue. The system test passed with 
this change.
I was suggesting a solution like this where we can know exactly when to `null` 
the reference. The change is not extensively tested though. (For example, test 
what happens if we remove a node and add it back, OR remove a node and add it 
to a different scenegraph)
However, in this case using `WeakReference` approach seems harmless. Using 
`WeakReference` for Listeners is not clean and may cause issues, but a 
`WeakReference` to Node should not cause any harm.

I would recommend earlier way to explicitly release references/resources when 
it is possible. That way we get to have the control instead of gc.


diff --git 
a/modules/javafx.graphics/src/main/java/javafx/scene/CssStyleHelper.java 
b/modules/javafx.graphics/src/main/java/javafx/scene/CssStyleHelper.java
index fd02c0c1ad..471d0071b5 100644
--- a/modules/javafx.graphics/src/main/java/javafx/scene/CssStyleHelper.java
+++ b/modules/javafx.graphics/src/main/java/javafx/scene/CssStyleHelper.java
@@ -36,6 +36,7 @@ import java.util.Set;
 
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.value.ChangeListener;
 import javafx.beans.value.WritableValue;
 import com.sun.javafx.css.CascadingStyle;
 import javafx.css.CssMetaData;
@@ -82,6 +83,14 @@ final class CssStyleHelper {
         this.triggerStates = new PseudoClassState();
     }
 
+    ChangeListener<Scene> sceneChangeListener;
+
+    static void dispose(CssStyleHelper styleHelper, Node node) {
+        styleHelper.resetToInitialValues(node);
+        styleHelper.firstStyleableAncestor = null;
+        node.sceneProperty().removeListener(styleHelper.sceneChangeListener);
+    }
+
     /**
      * Creates a new StyleHelper.
      */
@@ -158,7 +167,7 @@ final class CssStyleHelper {
                 // If this node had a style helper, then reset properties to 
their initial value
                 // since the node won't have a style helper after this call
                 if (node.styleHelper != null) {
-                    node.styleHelper.resetToInitialValues(node);
+                    dispose(node.styleHelper, node);
                 }
 
                 //
@@ -181,8 +190,14 @@ final class CssStyleHelper {
         // If this node had a style helper, then reset properties to their 
initial value
         // since the style map might now be different
         if (node.styleHelper != null) {
-            node.styleHelper.resetToInitialValues(node);
+            dispose(node.styleHelper, node);
         }
+        helper.sceneChangeListener = (ov, oldScene, newScene) -> {
+            if (newScene == null) {
+                helper.firstStyleableAncestor = null;
+            }
+        };
+        node.sceneProperty().addListener(helper.sceneChangeListener);
         return helper;
     }

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

PR: https://git.openjdk.java.net/jfx/pull/424

Reply via email to