Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8189280

Memory leak in SwingNode if Stage is not shown

    XMLWordPrintable

Details

    • x86
    • other

    Backports

      Description

        FULL PRODUCT VERSION :
        java version "9"
        Java(TM) SE Runtime Environment (build 9+181)
        Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)

        ADDITIONAL OS VERSION INFORMATION :
        Microsoft Windows [Version 10.0.15063]

        A DESCRIPTION OF THE PROBLEM :
        If a stage is never shown, a SwingNode will never be elgible for GC. If the stage is shown, it will eventually be removed by the GC

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        The memory leak is evident in a profiler. I used the NB profiler.

        Run the test program. Keep pressing the "Open Stage" button. Doing so will continually open intermediate stages, closing an existing one if it exists.

        If the intermediate stage was being shown (the stage.show() method at line 100 is not commented out), the SwingNodes will be collect appropriately. If the intermediate stages are not shown (the stage.show() method at line 100 is commented out), they will never be collected.

        Don't forget to use the -Djavafx.embed.singleThread=true option.


        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The SwingNodes will eventually be collected
        ACTUAL -
        No SwingNodes are collected if the intermediate stages are not shown

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        /*
         * To change this license header, choose License Headers in Project Properties.
         * To change this template file, choose Tools | Templates
         * and open the template in the editor.
         */
        package javafxmemoryleak;

        import javafx.application.Application;
        import javafx.embed.swing.SwingNode;
        import javafx.scene.Scene;
        import javafx.scene.control.Alert;
        import javafx.scene.control.Button;
        import javafx.scene.control.ProgressIndicator;
        import javafx.scene.layout.BorderPane;
        import javafx.scene.layout.HBox;
        import javafx.scene.layout.StackPane;
        import javafx.stage.Stage;
        import javax.swing.JLabel;

        public class JavaFXMemoryLeak extends Application {
        private Stage tempStage;

        @Override
        public void start(final Stage primaryStage) {
        Button openDialog = new Button();

        openDialog.setText("Open Dialog");
        openDialog.setOnAction(e -> openDialog(primaryStage));

        Button openStage = new Button();
        openStage.setText("Open Stage");
        openStage.setOnAction(e -> openStage(primaryStage));

        Button closeStage = new Button();
        closeStage.setText("Close Stage");
        closeStage.setOnAction(e -> closeStage());

        HBox root = new HBox();
        root.getChildren().add(openDialog);
        root.getChildren().add(openStage);
        root.getChildren().add(closeStage);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Memory Test");
        primaryStage.setScene(scene);
        primaryStage.show();
        }
        private void closeStage() {
        if (tempStage != null)
        tempStage.close();
        tempStage = null;
        }
        private void openDialog(Stage primaryStage) {
        StackPane root = new StackPane();
        ProgressIndicator pi = new ProgressIndicator();
        pi.parentProperty().addListener((obs, oldVal, newVal) -> System.out.println("Parent: " + newVal));
        pi.sceneProperty().addListener((obs, oldVal, newVal) -> {
        System.out.println("Dialog Scene: " + newVal);
        });
        root.getChildren().add(pi);

        Alert dialog = new Alert(Alert.AlertType.INFORMATION);
        dialog.getDialogPane().setContent(root);

        dialog.initOwner(primaryStage);
        dialog.showAndWait();

        }
        private void openStage(Stage primaryStage) {
        closeStage();
        BorderPane root = new BorderPane();
        SwingNode sw = new SwingNode();
        sw.setContent(new JLabel("SWING"));
        root.centerProperty().set(sw);

        // ProgressIndicator pi = new ProgressIndicator();
        // pi.parentProperty().addListener((obs, oldVal, newVal) -> System.out.println("Parent: " + newVal));
        // pi.sceneProperty().addListener((obs, oldVal, newVal) -> {
        // System.out.println("Scene: " + newVal);
        // });
        // root.centerProperty().set(pi);
        final Stage stage = new Stage();
        Button btn = new Button();
        btn.setText("Stage Close");
        btn.setOnAction(e -> {
        stage.close();
        });

        root.bottomProperty().set(btn);

        Scene scene = new Scene(root, 150, 100);
        stage.setScene(scene);
        tempStage = stage;
        //If we don't show the stage, resources are never released
        // stage.show();
        }

        /**
        * @param args the command line arguments
        */
        public static void main(String[] args) {
        System.out.println("java.version = " + System.getProperty("java.version"));
        System.out.println("java.runtime.version = " + System.getProperty("java.runtime.version"));
        launch(args);
        }

        }

        ---------- END SOURCE ----------

        Attachments

          Issue Links

            Activity

              People

                psadhukhan Prasanta Sadhukhan
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                8 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved: