JavaFX8-TableView泄漏(TableMenuButton)

JavaFX8-TableView泄漏(TableMenuButton),java,javafx,memory-leaks,tableview,Java,Javafx,Memory Leaks,Tableview,我有一个JavaFXTableView,它可以动态更改列属性(宽度、可见性),以实现多个“自定义设置/列预设” 每当我更改列设置时,我注意到大量未收集的内存。试图用普通java代码重现这种情况 并且能够在附加程序的情况下完成: 注意:启动程序后,一切正常!内存按预期收集。当我们单击列标题右侧的TableMenuButton(加号)时,事情似乎变得非常糟糕。它长大了 无休止的记忆错误 公共类TableViewMenuButtonLeak扩展应用程序{ 公共静态void main(字符串[]arg

我有一个JavaFXTableView,它可以动态更改列属性(宽度、可见性),以实现多个“自定义设置/列预设”

每当我更改列设置时,我注意到大量未收集的内存。试图用普通java代码重现这种情况 并且能够在附加程序的情况下完成:

注意:启动程序后,一切正常!内存按预期收集。当我们单击列标题右侧的TableMenuButton(加号)时,事情似乎变得非常糟糕。它长大了 无休止的记忆错误

公共类TableViewMenuButtonLeak扩展应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公众假期开始(阶段){
//**设置表**
最终的TableView表格=新的TableView();
//按下“桌面菜单”按钮时,一切都变得疯狂
table.setTableMenuButtonVisible(true);
//生成一组列
对于(int i=0;i<4;i++){
TableColumn column1=新的TableColumn(“列”+i);
列1.setCellValueFactory(新属性ValueFactory(“列”+i));
table.getColumns().add(column1);
}
//**永远更改表格设置**
可运行r=()->{
while(true){
Platform.runLater(()->{
table.getColumns().stream().forEach((c)->c.setPrefWidth(Math.random()*300));
table.getColumns().stream().forEach((c)->c.setVisible(Math.random()>0.5?true:false));
});
试一试{
睡眠(1);
}捕获(中断异常e){}
}
};
螺纹t=新螺纹(r);
t、 setDaemon(true);
t、 start();
//**表演材料**
stage.setTitle(!!!!点击表格右侧的“TableMenuButton”(加号)!!!);
场景=新场景(表);
舞台布景宽度(600);
舞台设置高度(600);
舞台场景;
stage.show();
}
公共静态类记录{
私人财产专栏1;
私人财产专栏2;
公共记录(字符串列1、字符串列2){
this.column1=新的SimpleStringProperty(column1);
this.column2=新的SimpleStringProperty(column2);
}
公共字符串getColumn1(){
返回column1.get();
}
public StringProperty column1Property(){
返回列1;
}
公共字符串getColumn2(){
返回column2.get();
}
public StringProperty column2Property(){
返回列2;
}
}
}
分析heapdump可以发现有数千个 “StackPane”、“ContextMenuContent$MenuLabel”和“ContextMenuContent$MenuItemContainer”实例

我的问题是:

  • 这是已知的bug吗?(至少我没有找到泄漏描述 与此相符,但我当然可能会错过)
  • 你有过同样的经历吗
  • 有人知道这个问题的解决方法吗
我用JDK 1_8_(60/91/102)对此进行了测试。所有虚拟机都表现出相同的行为

public class TableViewMenuButtonLeak extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {

        // ** SETUP TABLE **
        final TableView<Record> table = new TableView<>();

        // things go crazy when the table menu button was pressed
        table.setTableMenuButtonVisible(true);

        //generate a bunch of columns
        for(int i = 0; i < 4; i++) {
            TableColumn<Record, String> column1 = new TableColumn<>("column"+i);
            column1.setCellValueFactory(new PropertyValueFactory<Record, String>("column"+i));
            table.getColumns().add(column1);
        }

        // ** CHANGE TABLE SETTINGS FOREVER **
        Runnable r = () -> {
            while(true) {
                Platform.runLater(() -> {
                        table.getColumns().stream().forEach((c) -> c.setPrefWidth(Math.random() * 300));
                        table.getColumns().stream().forEach((c) -> c.setVisible(Math.random() > 0.5 ? true : false));
                });

                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {}
            }
        };

        Thread t = new Thread(r);
        t.setDaemon(true);
        t.start();


        // ** SHOW STUFF **
        stage.setTitle("!!!! Do click onto the \"TableMenuButton\" on the right side of the table (PLUS sign) !!!");
        Scene scene = new Scene(table);
        stage.setWidth(600);
        stage.setHeight(600);
        stage.setScene(scene);
        stage.show();
    }

    public static class Record {

        private final StringProperty column1;
        private final StringProperty column2;

        public Record(String column1, String column2) {
            this.column1 = new SimpleStringProperty(column1);
            this.column2 = new SimpleStringProperty(column2);
        }

        public String getColumn1() {
            return column1.get();
        }

        public StringProperty column1Property() {
            return column1;
        }

        public String getColumn2() {
            return column2.get();
        }

        public StringProperty column2Property() {
            return column2;
        }
    }
}