JavaFX 滚动表更新性能会随着时间的推移而降低

我有一个表视图,显示最后N个项目,顶部的新项目,从底部删除项目等...似乎正在发生的事情是CPU负载随着时间的推移而增加,以至于同一台计算机上的其他X应用程序变得迟钝。

平台详细信息:Redhat 6.7、32 位、Java 1.8u40

我尝试过的东西

  • 引入 runLater() - 原始代码从非 FX 线程更新了可观察列表 - 显然这是错误的
  • 优化 - 仅当尚未进行更新时,才将新的 Runnable 放在 JavaFX 应用程序线程上
  • 优化 - 批量更新可观察列表而不是单个添加
  • 使用jvisual VM来识别任何内存泄漏,找不到任何东西。
  • 我试图重新创建这个
    • Windows 7(在金属上)- JDK 8u40 64 位 = >不会出现
    • Ubuntu 16.04 JDK 8u40 64 位(在装有 vmwgfx 的 VM 内部)=>不会发生
    • Ubuntu 16.04 OpenJDK + OpenJFX latest (8u91) (在金属上) = >确实发生

JVisual VM - Newish 硬件上的 Redhat 6u7 (32 位)

Redhat 6u7

JVisual VM - 旧硬件上的 Ubuntu 16.04 (64 位) (2008 iMac)

Ubuntu 16.04 on Intel iMac

这个问题是大型应用程序的一部分,但我在下面将其隔离为一个较小的示例。这使得其他应用程序在几分钟后变得迟钝,但仅在Redhat 6u7平台上。

public class TableUpdater extends Application {
    private int maxItems = 30;
    private AtomicBoolean pending = new AtomicBoolean();
    public class Thing {
        private String foo;
        public Thing(String foo) {
            this.foo = foo;
        }
        public String getFoo() {
            return foo;
        }
        @Override
        public int hashCode() {
            return foo.hashCode();
        }
        @Override
        public boolean equals(Object obj) {
            if (! (obj instanceof Thing)) {
                return false;
            }
            return ((Thing)obj).foo.equals(foo);
        }
    }

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

    private int counter = 0;
    private ObservableList<Thing> data;
    private List<Thing> itemsToAdd = Collections.synchronizedList(new ArrayList<Thing>());

    @Override
    public void start(Stage primaryStage) throws Exception {
        TableView<Thing> table = new TableView<>();
        data = FXCollections.observableArrayList();
        table.setItems(data);

        TableColumn<Thing, String> fooCol = new TableColumn<>("Foo");
        fooCol.setCellValueFactory(new PropertyValueFactory<Thing, String>("foo"));
        table.getColumns().addAll(fooCol);

        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
            add(new Thing(String.format("%08d", counter++)));
        }, 0, 2, TimeUnit.MILLISECONDS);

        primaryStage.setScene(new Scene(table));
        primaryStage.setWidth(400);
        primaryStage.setHeight(400);
        primaryStage.show();
    }

    private void add(Thing thing) {
        itemsToAdd.add(thing);

        if (!pending.getAndSet(true)) {
            Platform.runLater(() -> {
                synchronized (itemsToAdd) {
                    Collections.reverse(itemsToAdd);
                    data.addAll(0, itemsToAdd);
                    itemsToAdd.clear();
                }
                if (data.size() > maxItems) {
                    data.remove(maxItems, data.size());
                }
                pending.set(false);
            });
        }
    }
}

问题

  • 此问题是否与我更新表的方式有关,还是与底层错误有关?
  • 有没有更有效的方法来更新表?

答案 1

尝试使用 G1GC 垃圾回收器。我有一个类似但不完全相同的问题(表视图中的大量持久对象),这个问题通过使用G1GC解决了。

java XX:+UseG1GC


答案 2

推荐