Adding three (or more) TreeItems at a time, to a TreeView that is not part of the scene graph, causes an infinite TreeCell leak, and eventually an OOM.
To reproduce the problem, follow the steps described in the sample below:
1. select TreeItem1 (without selection the problem doesn't occur - fortunately)
2. remove the TreeView
3. add three TreeItems at a time
Fortunately, this problem is no longer reproducible on Java8, but it is reproducible on the latest Java7 update.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TreeCellLeakTest extends Application {
private VBox vBox;
private TreeView<String> treeView;
private int itemCount = 1;
public TreeCellLeakTest() {
}
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
Label instructionLabel = new Label("Select TreeItem1, click the first button, then the last one, to see the problem.");
treeView = new TreeView<String>();
TreeItem<String> rootItem = new TreeItem<String>("Root TreeItem");
rootItem.setExpanded(true);
treeView.setRoot(rootItem);
addTreeItem();
Button btn1 = new Button("Remove the TreeView from its parent");
btn1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent arg0) {
vBox.getChildren().remove(treeView);
}
});
Button btn2 = new Button("Bring the TreeView back");
btn2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent arg0) {
vBox.getChildren().add(1, treeView);
}
});
Button btn3 = new Button("Add Three TreeItems at a time");
btn3.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent arg0) {
addTreeItem();
addTreeItem();
addTreeItem();
}
});
vBox = new VBox();
vBox.setSpacing(20);
vBox.setPadding(new Insets(50));
vBox.getChildren().addAll(instructionLabel, treeView, btn1, btn2, btn3);
VBox.setVgrow(treeView, Priority.ALWAYS);
Scene scene = new Scene(vBox);
stage.setScene(scene);
stage.setTitle("TreeCell Leak Test");
stage.show();
}
private void addTreeItem() {
treeView.getRoot().getChildren().add(new TreeItem<String>("TreeItem " + itemCount));
itemCount++;
}
}
To reproduce the problem, follow the steps described in the sample below:
1. select TreeItem1 (without selection the problem doesn't occur - fortunately)
2. remove the TreeView
3. add three TreeItems at a time
Fortunately, this problem is no longer reproducible on Java8, but it is reproducible on the latest Java7 update.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TreeCellLeakTest extends Application {
private VBox vBox;
private TreeView<String> treeView;
private int itemCount = 1;
public TreeCellLeakTest() {
}
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
Label instructionLabel = new Label("Select TreeItem1, click the first button, then the last one, to see the problem.");
treeView = new TreeView<String>();
TreeItem<String> rootItem = new TreeItem<String>("Root TreeItem");
rootItem.setExpanded(true);
treeView.setRoot(rootItem);
addTreeItem();
Button btn1 = new Button("Remove the TreeView from its parent");
btn1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent arg0) {
vBox.getChildren().remove(treeView);
}
});
Button btn2 = new Button("Bring the TreeView back");
btn2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent arg0) {
vBox.getChildren().add(1, treeView);
}
});
Button btn3 = new Button("Add Three TreeItems at a time");
btn3.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent arg0) {
addTreeItem();
addTreeItem();
addTreeItem();
}
});
vBox = new VBox();
vBox.setSpacing(20);
vBox.setPadding(new Insets(50));
vBox.getChildren().addAll(instructionLabel, treeView, btn1, btn2, btn3);
VBox.setVgrow(treeView, Priority.ALWAYS);
Scene scene = new Scene(vBox);
stage.setScene(scene);
stage.setTitle("TreeCell Leak Test");
stage.show();
}
private void addTreeItem() {
treeView.getRoot().getChildren().add(new TreeItem<String>("TreeItem " + itemCount));
itemCount++;
}
}