JavaFX VirtualFlow中TableRow未被GC回收:是否为内存泄漏?
TableView清空数据后TableRow实例未被垃圾回收,是内存泄漏还是预期行为?
我在使用VirtualFlow时遇到一个情况:在TableView中,我原本认为当TableRow实例不再被使用时应该会被垃圾回收(GC),但按照以下步骤操作后出现了不符合预期的现象:
- 步骤1:打开包含空TableView的窗口,检查内存中没有TableRow实例,符合预期。
- 步骤2:向TableView填充数据,根据界面空间需求生成了38个TableRow实例。
- 步骤3:清空TableView中的数据(此时TableView显示占位符信息),多次手动触发GC后检查内存,发现所有38个TableRow实例仍然被VirtualFlow的cells ArrayLinkedList强引用,引用关系如图所示:

请问这是内存泄漏问题,还是JavaFX设计时就考虑到的预期行为?
以下是可复现该场景的验证代码:
import javafx.application.Application; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class TableViewMemoryLeakDemo extends Application { public static void main(String... a) { Application.launch(a); } @Override public void start(final Stage primaryStage) { final ObservableList<TableDataObj> items = FXCollections.observableArrayList(); final TableView<TableDataObj> table = buildTable(); table.setItems(items); Button clear = new Button("Clear All"); clear.setOnAction(e -> { items.clear(); }); Button add = new Button("Add 50 Rows"); add.setOnAction(e -> { for (int i = 0 + 1; i < 50; i++) { final String firstName = "First Name " + i; final String lastName = "Last Name " + i; final String city = "City " + i; items.add(new TableDataObj(i, firstName, lastName, city)); } }); HBox row = new HBox(add, clear); row.setSpacing(10); final VBox root = new VBox(row, table); root.setSpacing(10); root.setPadding(new Insets(10)); VBox.setVgrow(table, Priority.ALWAYS); final Scene sc = new Scene(root, 1200, 950); primaryStage.setScene(sc); primaryStage.setTitle("TableView MemoryLeak Demo " + System.getProperty("javafx.runtime.version")); primaryStage.show(); } private TableView<TableDataObj> buildTable() { final TableColumn<TableDataObj, Integer> idCol = new TableColumn<>(); idCol.setText("Id"); idCol.setCellValueFactory(param -> param.getValue().idProperty().asObject()); idCol.setPrefWidth(100); final TableColumn<TableDataObj, String> fnCol = new TableColumn<>(); fnCol.setText("First Name"); fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty()); fnCol.setPrefWidth(150); final TableColumn<TableDataObj, String> lnCol = new TableColumn<>(); lnCol.setText("Last Name"); lnCol.setCellValueFactory(param -> param.getValue().lastNameProperty()); lnCol.setPrefWidth(150); final TableColumn<TableDataObj, String> cityCol = new TableColumn<>(); cityCol.setText("City"); cityCol.setCellValueFactory(param -> param.getValue().cityProperty()); cityCol.setPrefWidth(150); final TableView<TableDataObj> tableView = new TableView<>(); tableView.getColumns().addAll(idCol, fnCol, lnCol, cityCol); return tableView; } /** * Data object. */ class TableDataObj { private final IntegerProperty id = new SimpleIntegerProperty(); private final StringProperty firstName = new SimpleStringProperty(); private final StringProperty lastName = new SimpleStringProperty(); private final StringProperty city = new SimpleStringProperty(); public TableDataObj(final int i, final String fn, final String ln, final String cty) { setId(i); setFirstName(fn); setLastName(ln); setCity(cty); } public StringProperty cityProperty() { return city; } public StringProperty firstNameProperty() { return firstName; } public int getId() { return id.get(); } public IntegerProperty idProperty() { return id; } public StringProperty lastNameProperty() { return lastName; } public void setCity(final String city1) { city.set(city1); } public void setFirstName(final String firstName1) { firstName.set(firstName1); } public void setId(final int idA) { id.set(idA); } public void setLastName(final String lastName1) { lastName.set(lastName1); } } }
内容的提问来源于stack exchange,提问作者Sai Dandem
相关产品推荐
相关产品推荐

