47215


JavaFX version: 8  
JDK: 1.8  
OS: Windows 10

開発中のアプリケーションでメモリリークが起きているため、以下のコードで検証をしました。

[code]

    package sample;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.layout.Pane;
    import javafx.stage.Stage;
    
    class CustomNode extends Pane {
    
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("Do finalize!!!");
        }
    }
    
    public class Main extends Application {
    
        private Button aButton = null;
        private Button bButton = null;
        private Pane container = new Pane();
    
        @Override
        public void start(Stage primaryStage) throws Exception{
            Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
    
            primaryStage.setTitle("Hello World");
            primaryStage.setScene(new Scene(root, 300, 275));
            primaryStage.show();
    
            aButton = (Button)root.lookup("#AButton");
            bButton = (Button)root.lookup("#BButton");
            aButton.setOnAction(event -> {
                System.out.println("AOnPushed");
                for (int i = 0; i < 10000; i++) {
                    CustomNode node = new CustomNode();
                    container.getChildren().add(node);
                }
            });
            bButton.setOnAction(event -> {
                System.out.println("BOnPushed");
                container.getChildren().removeAll();
            });
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
[/code]

  1. Aボタンを押すと、コンテナに生成したNodeオブジェクトを追加する。
  2. Bボタンを押すと、コンテナを空にする。
  3. VisualVM等でGCを実行する。

`2.`の段階で、コンテナからNodeオブジェクトは破棄されるため、Nodeオブジェクトを参照する要素がなくなる。 ->
GCの対象になる。というのが期待する動作です。しかし、実際にはコンテナを空にしてもNodeオブジェクトは破棄されません。  
このコードで何故メモリリークが発生してしまうのでしょうか？

**追記**

[code]

    package sample;
    
    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.stage.Stage;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    class CustomNode {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("Do finalize!!!");
        }
    
    }
    
    public class Main extends Application {
    
        private Button aButton = null;
        private Button bButton = null;
        private ObservableList<CustomNode> container = FXCollections.observableArrayList();
        // private List<CustomNode> container = new ArrayList<>();
    
        @Override
        public void start(Stage primaryStage) throws Exception{
            Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
    
            primaryStage.setTitle("Hello World");
            primaryStage.setScene(new Scene(root, 300, 275));
            primaryStage.show();
    
            aButton = (Button)root.lookup("#AButton");
            bButton = (Button)root.lookup("#BButton");
            aButton.setOnAction(event -> {
                System.out.println("AOnPushed");
                for (int i = 0; i < 10000; i++) {
                    CustomNode node = new CustomNode();
                    container.add(node);
                }
            });
            bButton.setOnAction(event -> {
                System.out.println("BOnPushed");
                // container.clear(); // clear()だとリークしなかった
                container.removeAll();
            });
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
[/code]

ObservableList<>を使うだけで同様の現象になったのでNodeクラス自体は関係なさそうです。


CC BY-SA 4.0
2018-08-03T08:48:13.657
47212
2023-07-05T19:08:58.320
2018-08-03T09:01:15.087
17238
17238
question
java java8 javafx
JavaFXのシーングラフでNodeオブジェクトがメモリリークする


自己解決しました。

removeAll()の仕様を勘違いしていました。可変長引数になっていて、渡した引数を削除するのですね。つまり引数なしのremoveAll();は何もしない。clear()が正解でした。失礼しました。


CC BY-SA 4.0
2018-08-03T09:37:02.587
47215
2023-07-05T19:08:58.320
2023-07-05T19:08:58.320
3060
17238
47212
answer