The sample below adds 300 child TreeItems with non-null graphics, one at a time. After the add is done, you can see that there are more than 5000 instances of TreeCellSkin, retaining around 120MB of memory.
If you run the same sample with addChildItem(false); (to add TreeItems with null graphics), there are only 21 instances of TreeCellSkin, retaining only about 5MB of memory.
Note that this is reproducible in the latest version of Java7, but not in Java8. So in case you will no longer fix this in Java7, can you please provide a simple workaround for it?
import java.util.concurrent.Executors;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
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 TreeCellSkinLeakTest extends Application {
private TreeView<String> treeView;
private int itemCount = 1;
public TreeCellSkinLeakTest() {
}
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
TreeItem<String> rootItem = new TreeItem<String>("Root TreeItem");
rootItem.setExpanded(true);
treeView = new TreeView<String>();
treeView.setRoot(rootItem);
Button addBtn = new Button("Add Child TreeItems");
addBtn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent arg0) {
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
for (int i = 0; i < 300; i++) {
Platform.runLater(new Runnable() {
public void run() {
addChildItem(true);
}
});
Thread.sleep(25);
}
return null;
}
};
Executors.newCachedThreadPool().execute(task);
}
});
VBox vBox = new VBox(20);
vBox.setPadding(new Insets(50));
vBox.getChildren().addAll(treeView, addBtn);
VBox.setVgrow(treeView, Priority.ALWAYS);
stage.setScene(new Scene(vBox));
stage.show();
}
private void addChildItem(boolean addGraphic) {
TreeItem<String> childItem = new TreeItem<String>("Child Item " + itemCount++);
if (addGraphic) {
childItem.setGraphic(new Label("<graphic>"));
}
treeView.getRoot().getChildren().add(childItem);
}
}
If you run the same sample with addChildItem(false); (to add TreeItems with null graphics), there are only 21 instances of TreeCellSkin, retaining only about 5MB of memory.
Note that this is reproducible in the latest version of Java7, but not in Java8. So in case you will no longer fix this in Java7, can you please provide a simple workaround for it?
import java.util.concurrent.Executors;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
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 TreeCellSkinLeakTest extends Application {
private TreeView<String> treeView;
private int itemCount = 1;
public TreeCellSkinLeakTest() {
}
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
TreeItem<String> rootItem = new TreeItem<String>("Root TreeItem");
rootItem.setExpanded(true);
treeView = new TreeView<String>();
treeView.setRoot(rootItem);
Button addBtn = new Button("Add Child TreeItems");
addBtn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent arg0) {
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
for (int i = 0; i < 300; i++) {
Platform.runLater(new Runnable() {
public void run() {
addChildItem(true);
}
});
Thread.sleep(25);
}
return null;
}
};
Executors.newCachedThreadPool().execute(task);
}
});
VBox vBox = new VBox(20);
vBox.setPadding(new Insets(50));
vBox.getChildren().addAll(treeView, addBtn);
VBox.setVgrow(treeView, Priority.ALWAYS);
stage.setScene(new Scene(vBox));
stage.show();
}
private void addChildItem(boolean addGraphic) {
TreeItem<String> childItem = new TreeItem<String>("Child Item " + itemCount++);
if (addGraphic) {
childItem.setGraphic(new Label("<graphic>"));
}
treeView.getRoot().getChildren().add(childItem);
}
}