-
Bug
-
Resolution: Cannot Reproduce
-
P4
-
jfx20
-
x86_64
-
windows_10
A DESCRIPTION OF THE PROBLEM :
If you have a TableView and use setGraphic() to add a VBox with some children (the more the better) and then add the vbox x-times and always scroll down to the last element the memory keeps getting up. Even if you trigger a garbage collect, the memory will not be released again.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I worked out a code example and added it to the report. To reproduce: create a TableView, use setGraphic() in a cell and add a VBox with lots of children there. Then keep adding rows with big VBoxes and scroll down to the last element.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would expect that at some point the memory goes down again
ACTUAL -
The memory never goes down, it keeps getting up
---------- BEGIN SOURCE ----------
import java.lang.management.ManagementFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.MapValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Bug extends Application {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void start(Stage primaryStage) throws Exception {
long startTime = System.nanoTime();
TableView<Map<String, Object>> tableView = new TableView<>();
ObservableList<Map<String, Object>> data = FXCollections.observableArrayList();
tableView.setItems(data);
TableColumn<Map<String, Object>, String> firstCol = new TableColumn<>("first");
firstCol.setPrefWidth(150);
TableColumn<Map<String, Object>, String> secondCol = new TableColumn<>("second");
tableView.getColumns().addAll(firstCol, secondCol);
firstCol.setCellValueFactory(new MapValueFactory("first"));
secondCol.setCellFactory(param -> new TableCell<Map<String, Object>, String>() {
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
VBox box = new VBox();
box.getChildren().addAll(new Label("We have"),
new Label(String.valueOf(getTableView().getItems().size())), new Label("items"),
new Label("in the table"),
new Label("running time: " + TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime) + " seconds"),
new Label("memory used: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() + " bytes"),
new Label("and a lot"),
new Label("labels"),
new Text("and"),
new Text("Text"),
new Text("and"),
new Text("such")
);
setGraphic(box);
}
});
BorderPane root = new BorderPane();
root.setCenter(tableView);
Scene scene = new Scene(root, 300, 400);
primaryStage.setScene(scene);
primaryStage.show();
Runnable beeper = new Runnable() {
@Override
public void run() {
Map<String, Object> map = new HashMap<>();
map.put("first", "test" + System.currentTimeMillis());
data.add(map);
}
};
ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(beeper, 1, 2, TimeUnit.MILLISECONDS);
scheduler.schedule(new Runnable() {
@Override
public void run() {
beeperHandle.cancel(true);
}
}, 60 * 60L, TimeUnit.SECONDS);
Runnable beeperRefresh = new Runnable() {
@Override
public void run() {
Platform.runLater(() -> {
tableView.scrollTo(tableView.getItems().size());
});
}
};
ScheduledFuture<?> beeperHandler2 = scheduler.scheduleAtFixedRate(beeperRefresh, 1, 5, TimeUnit.SECONDS);
scheduler.schedule(new Runnable() {
@Override
public void run() {
beeperHandler2.cancel(true);
}
}, 60 * 60L, TimeUnit.SECONDS);
}
}
---------- END SOURCE ----------
If you have a TableView and use setGraphic() to add a VBox with some children (the more the better) and then add the vbox x-times and always scroll down to the last element the memory keeps getting up. Even if you trigger a garbage collect, the memory will not be released again.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I worked out a code example and added it to the report. To reproduce: create a TableView, use setGraphic() in a cell and add a VBox with lots of children there. Then keep adding rows with big VBoxes and scroll down to the last element.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would expect that at some point the memory goes down again
ACTUAL -
The memory never goes down, it keeps getting up
---------- BEGIN SOURCE ----------
import java.lang.management.ManagementFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.MapValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Bug extends Application {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void start(Stage primaryStage) throws Exception {
long startTime = System.nanoTime();
TableView<Map<String, Object>> tableView = new TableView<>();
ObservableList<Map<String, Object>> data = FXCollections.observableArrayList();
tableView.setItems(data);
TableColumn<Map<String, Object>, String> firstCol = new TableColumn<>("first");
firstCol.setPrefWidth(150);
TableColumn<Map<String, Object>, String> secondCol = new TableColumn<>("second");
tableView.getColumns().addAll(firstCol, secondCol);
firstCol.setCellValueFactory(new MapValueFactory("first"));
secondCol.setCellFactory(param -> new TableCell<Map<String, Object>, String>() {
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
VBox box = new VBox();
box.getChildren().addAll(new Label("We have"),
new Label(String.valueOf(getTableView().getItems().size())), new Label("items"),
new Label("in the table"),
new Label("running time: " + TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime) + " seconds"),
new Label("memory used: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() + " bytes"),
new Label("and a lot"),
new Label("labels"),
new Text("and"),
new Text("Text"),
new Text("and"),
new Text("such")
);
setGraphic(box);
}
});
BorderPane root = new BorderPane();
root.setCenter(tableView);
Scene scene = new Scene(root, 300, 400);
primaryStage.setScene(scene);
primaryStage.show();
Runnable beeper = new Runnable() {
@Override
public void run() {
Map<String, Object> map = new HashMap<>();
map.put("first", "test" + System.currentTimeMillis());
data.add(map);
}
};
ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(beeper, 1, 2, TimeUnit.MILLISECONDS);
scheduler.schedule(new Runnable() {
@Override
public void run() {
beeperHandle.cancel(true);
}
}, 60 * 60L, TimeUnit.SECONDS);
Runnable beeperRefresh = new Runnable() {
@Override
public void run() {
Platform.runLater(() -> {
tableView.scrollTo(tableView.getItems().size());
});
}
};
ScheduledFuture<?> beeperHandler2 = scheduler.scheduleAtFixedRate(beeperRefresh, 1, 5, TimeUnit.SECONDS);
scheduler.schedule(new Runnable() {
@Override
public void run() {
beeperHandler2.cancel(true);
}
}, 60 * 60L, TimeUnit.SECONDS);
}
}
---------- END SOURCE ----------
- relates to
-
JDK-8307538 Memory leak in TreeTableView when calling refresh
- Resolved