1

I am experiencing memory leaks with TreeTableView when TableMenu is enabled. Steps to reproduce is simple. I have done some research why it's happening but will leave it to experts here to throw some light.

Run the embedded code with -Xmx 256m to reduce wait time. I am running with JDK 1.8.0_121

Both steps must be performed in sequence.

  1. Click on the Table Menu Menu Button the right top corner (+) just once no need to select any menu item.
  2. Then Click (X) on the DYNAMIC column (Give it few secs to OOM)

        package hellofx;
    
        import javafx.application.Application;
        import javafx.application.Platform;
        import javafx.scene.Scene;
        import javafx.scene.control.Button;
        import javafx.scene.control.TreeItem;
        import javafx.scene.control.TreeTableCell;
        import javafx.scene.control.TreeTableColumn;
        import javafx.scene.control.TreeTableView;
        import javafx.stage.Stage;
    
        public class TreeTableMemoryLeak extends Application {
            public static void main(String[] args) {
                launch(args);
            }
    
            @Override
            public void start(Stage stage) {
                TreeTableView<Object> otable = buildTableView();
                Platform.runLater(()->{
                    Scene scene = new Scene(otable,otable.getWidth(),otable.getHeight());
                    stage.setScene(scene);
                    stage.show();
                });
            }
    
            private TreeTableView<Object> buildTableView() {
                TreeTableView<Object> table = new TreeTableView<>();
                TreeTableColumn<Object, String> indexCol = new TreeTableColumn<>("Index");
                indexCol.setCellFactory(column -> {
                    return new TreeTableCell<Object, String>() {
                        @Override
                        protected void updateItem(String item, boolean empty) {
                            setText(String.valueOf(getIndex()));
                        }
                    };
                });
                TreeTableColumn<Object, String> dynCol = new TreeTableColumn<>("DYNAMIC");
                dynCol.setGraphic(new Button("X"){
                    {
                        //ATTENTION 3 (On click of X remove all columns except first column)
                        setOnAction((e)->dynCol.getColumns().removeIf(c->c!=dynCol.getColumns().get(0)));
                    }
                });
                //ATTENTION 1
                table.setTableMenuButtonVisible(true);
    
                //ATTENTION 2 (39 is the magic number anything higher it will OOM on my device I have total 6G physical.)
                for(int i=0;i<39;i++){
                    dynCol.getColumns().add(new TreeTableColumn<>(String.valueOf(i)));
                }
                table.getColumns().addAll(indexCol,dynCol);
                table.setEditable(true);
                table.setRoot(new TreeItem<Object>());
                return table;
            }
        }
    

    Running Application Image

  • What happens if you use `dynCol.getColumns().remove(1, dynCol.getColumns().size())` instead? – VGR Nov 24 '17 at 03:44
  • Good News and Bad News, I tried after you mentioned.. Guess what NO OOM with magic number 39. So then I tried to amplify the problem and it now it goes OOM at 179 precisely My theory is when it is trying to remove columns it keeps scanning the context menu and removes items. In the process there is some reallocations happening whose reference are not being released until the process is complete. –  Nov 25 '17 at 18:24
  • This appears to be a bug. 256m is probably too small for a JavaFX application (the bare minimum for Java itself is 128m), but I ran many tests with many different column counts using larger memory limits, and showing the table menu button’s menu first always seems to guarantee an OutOfMemoryError. – VGR Nov 25 '17 at 19:58

0 Answers0