【发布时间】:2016-11-06 07:32:37
【问题描述】:
我有一个 TableView,它显示最后 N 个项目、顶部的新项目、从底部删除的项目等......似乎正在发生的事情是 CPU 负载随着时间的推移而增加,以至于同一台机器上的其他 X 应用程序变得迟缓。
平台详情:Redhat 6.7、32 位、Java 1.8u40
我尝试过的事情
- 引入 runLater() - 原始代码从非 FX 线程更新了可观察列表 - 显然这是错误的
- 优化 - 如果没有正在进行的更新,则仅在 JavaFX 应用程序线程上放置新的 Runnables
- 优化 - Observable 列表的批量更新,而不是单个添加
- 使用 jvisual VM 识别任何内存泄漏,找不到任何东西。
- 我试图重新创建这个
- Windows 7(金属上)- JDK 8u40 64 位 => 不发生
- Ubuntu 16.04 JDK 8u40 64 位(在带有 vmwgfx 的 VM 内)=> 不会发生
- Ubuntu 16.04 OpenJDK + OpenJFX 最新版本 (8u91)(在金属上)=> 会发生
JVisual VM - 新硬件上的 Redhat 6u7(32 位)
JVisual VM - 旧硬件 (2008 iMac) 上的 Ubuntu 16.04(64 位)
此问题是较大应用程序的一部分,但我已将其隔离为下面的较小示例。这会使其他应用在几分钟后变得迟缓,但仅限于 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);
});
}
}
}
问题
- 此问题与我更新表的方式或潜在错误有关吗?
- 还有更高效的表格更新方法吗?
【问题讨论】:
-
如果你要按顺序添加它,你可以在没有执行器服务的情况下完成它。而且您不需要同步块,因为列表本身已经同步
-
我已经在 CentOS 6.8 x86(安装了最新更新)和 Oracle 的 JDK 8u40 x86(在虚拟机中)进行了尝试。我对缓慢的其他应用程序没有任何问题。但是对于您的示例,我的堆大小最大为 45mb,而不像您的最大超过 100mb。
-
Windows 和 Ubuntu 16.04 的“金属”是否相同?你有什么显卡,安装了什么驱动程序,尤其是在 linux 上?
-
Ubuntu 上的失败案例是在带有标准 radeon 驱动程序的“a01:00.0 VGA 兼容控制器:Advanced Micro Devices, Inc. [AMD/ATI] RV530/M56-P [Mobility Radeon X1600]”上。明天我会详细介绍 Redhat 机器(在办公室)
-
java、ati 和 X 有一个“类似”的错误,但它是在一个非常旧的 Ubuntu 版本中,所以我认为这不再有效,但可能是一个很好的起点。也许您可以在其他带有英特尔或英伟达显卡的硬件上尝试相同的设置?bugs.launchpad.net/ubuntu/+source/sun-java6/+bug/250931
标签: java multithreading performance javafx javafx-8