changeset 11180:eedba0ab9a0b

8216377: Fix memoryleak for initial nodes of Window 8207837: Indeterminate ProgressBar does not animate if content is added after scene is set on window Summary: Add or remove the windowShowingChangedListener when the scene changes Reviewed-by: arapte, kcr Contributed-by: fk@sandec.de
author kcr
date Tue, 22 Jan 2019 09:08:36 -0800
parents 2878dcdb7af4
children b1232b8e8de0
files modules/javafx.graphics/src/main/java/javafx/scene/Node.java tests/system/src/test/java/test/javafx/scene/InitialNodesMemoryLeakTest.java
diffstat 2 files changed, 120 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/modules/javafx.graphics/src/main/java/javafx/scene/Node.java	Fri Jan 18 14:16:14 2019 -0800
+++ b/modules/javafx.graphics/src/main/java/javafx/scene/Node.java	Tue Jan 22 09:08:36 2019 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1078,9 +1078,20 @@
         // isTreeShowing needs to take into account of Window's showing
         if (oldScene != null) {
             oldScene.windowProperty().removeListener(sceneWindowChangedListener);
+
+            Window window = oldScene.windowProperty().get();
+            if (window != null) {
+                window.showingProperty().removeListener(windowShowingChangedListener);
+            }
         }
         if (newScene != null) {
             newScene.windowProperty().addListener(sceneWindowChangedListener);
+
+            Window window = newScene.windowProperty().get();
+            if (window != null) {
+                window.showingProperty().addListener(windowShowingChangedListener);
+            }
+
         }
         updateTreeShowing();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/system/src/test/java/test/javafx/scene/InitialNodesMemoryLeakTest.java	Tue Jan 22 09:08:36 2019 -0800
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.javafx.scene;
+
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import javafx.stage.WindowEvent;
+
+import junit.framework.Assert;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import test.util.Util;
+import static org.junit.Assert.fail;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+
+public class InitialNodesMemoryLeakTest {
+
+    static CountDownLatch startupLatch;
+    static WeakReference<Group> groupWRef;
+    static Stage stage;
+
+    public static class TestApp extends Application {
+
+        @Override
+        public void start(Stage primaryStage) throws Exception {
+            stage = primaryStage;
+            Group group = new Group();
+            groupWRef = new WeakReference<>(group);
+            Group root = new Group(group);
+            stage.setScene(new Scene(root));
+
+            stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e -> {
+                Platform.runLater(() -> {
+                    root.getChildren().clear();
+                    startupLatch.countDown();
+                });
+            });
+            stage.show();
+        }
+    }
+
+    @BeforeClass
+    public static void initFX() {
+        startupLatch = new CountDownLatch(1);
+        new Thread(() -> Application.launch(InitialNodesMemoryLeakTest.TestApp.class, (String[])null)).start();
+        try {
+            if (!startupLatch.await(15, TimeUnit.SECONDS)) {
+                fail("Timeout waiting for FX runtime to start");
+            }
+        } catch (InterruptedException ex) {
+            fail("Unexpected exception: " + ex);
+        }
+    }
+
+    @Test
+    public void testRootNodeMemoryLeak() throws Exception {
+        for (int j = 0; j < 10; j++) {
+            System.gc();
+            System.runFinalization();
+
+            if (groupWRef.get() == null) {
+                break;
+            }
+
+            Util.sleep(500);
+        }
+        Assert.assertNull("Couldn't collect Node", groupWRef.get());
+    }
+
+    @AfterClass
+    public static void teardownOnce() {
+        Platform.runLater(() -> {
+            stage.hide();
+            Platform.exit();
+        });
+    }
+}