在最小化的 RDP 会话中调用重绘时使用大量 CPU 的 Swing
Swing using lots of CPU when calling repaint in a minimized RDP session
当 运行 虚拟机中的 Swing 应用程序时,我观察到 Java 8(多个版本,特别是 1.8.0_111)的一些奇怪行为。 VM 是 VMware 中的 Windows 10 台机器 运行,我正在对其进行远程桌面处理。我没有尝试使用实际的桌面而不是虚拟机来执行此操作,但我计划尽快删除一个额外的故障点。
我已经成功地用这个最小程序重现了它:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
for (int i = 0; i < 3; i++) {
JPanel subpanel = new JPanel();
JComboBox<?> box = new JComboBox<>();
subpanel.add(box);
panel.add(subpanel);
}
frame.add(panel);
frame.pack();
frame.setVisible(true);
Timer timer = new Timer(1000, e -> {
frame.repaint();
});
timer.setRepeats(true);
timer.start();
});
}
现在,如果我正常启动它,它会重新绘制,完全没有问题,正如预期的那样,只有一个包含 3 个空组合框的框架。如果我最小化 RDP 会话 window,就会出现问题。如果发生这种情况(并且框架未图标化),Swing 将开始消耗不健康的 CPU 数量,直到我再次打开 RDP window。
我已经尝试进一步最小化代码示例,但是将组合框计数减少到 2,删除 subpanel
或设置单次触发计时器(而不是重复,即使重绘会在RDP 被最小化)都阻止了错误的发生。
这是 CPU 利用率图表:
http://i67.tinypic.com/23rwglx.png
我已经尝试在这些峰值期间对应用程序进行分析,以尝试查看到底发生了什么。这是 JVisualVM 中分析器的结果:
http://i68.tinypic.com/apdwed.png
和采样器(删除包过滤器后):
http://i67.tinypic.com/2071735.png
我无法轻易看出 ProcessingRunnable
中的 CPU 是什么。有没有人体验过 Swing 突然没有屏幕可以绘制时的表现?
我已将此作为错误报告发布给 Oracle。我会在 link.
出现任何细节(被接受或拒绝)时更新此答案
几个 similar bugs 已经发布了 "Cannot reproduce" 作为解决方案,但是它们不涉及虚拟机,只涉及 RDP 会话(我无法通过 RDPing 到我的工作桌面,而不是虚拟机)。
我确实找到了解决方法 - 显然从 D3D 堆栈切换并强制使用 OpenGL 堆栈(启动时的 -Dsun.java2d.d3d=false
选项)可以防止这种情况发生。我现在添加了一些代码来检查应用程序是否在 VM 上启动并相应地设置选项。
编辑
错误报告已被接受,但目前在 "Cannot reproduce" 中。 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8191018
当 运行 虚拟机中的 Swing 应用程序时,我观察到 Java 8(多个版本,特别是 1.8.0_111)的一些奇怪行为。 VM 是 VMware 中的 Windows 10 台机器 运行,我正在对其进行远程桌面处理。我没有尝试使用实际的桌面而不是虚拟机来执行此操作,但我计划尽快删除一个额外的故障点。
我已经成功地用这个最小程序重现了它:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
for (int i = 0; i < 3; i++) {
JPanel subpanel = new JPanel();
JComboBox<?> box = new JComboBox<>();
subpanel.add(box);
panel.add(subpanel);
}
frame.add(panel);
frame.pack();
frame.setVisible(true);
Timer timer = new Timer(1000, e -> {
frame.repaint();
});
timer.setRepeats(true);
timer.start();
});
}
现在,如果我正常启动它,它会重新绘制,完全没有问题,正如预期的那样,只有一个包含 3 个空组合框的框架。如果我最小化 RDP 会话 window,就会出现问题。如果发生这种情况(并且框架未图标化),Swing 将开始消耗不健康的 CPU 数量,直到我再次打开 RDP window。
我已经尝试进一步最小化代码示例,但是将组合框计数减少到 2,删除 subpanel
或设置单次触发计时器(而不是重复,即使重绘会在RDP 被最小化)都阻止了错误的发生。
这是 CPU 利用率图表:
http://i67.tinypic.com/23rwglx.png
我已经尝试在这些峰值期间对应用程序进行分析,以尝试查看到底发生了什么。这是 JVisualVM 中分析器的结果:
http://i68.tinypic.com/apdwed.png
和采样器(删除包过滤器后):
http://i67.tinypic.com/2071735.png
我无法轻易看出 ProcessingRunnable
中的 CPU 是什么。有没有人体验过 Swing 突然没有屏幕可以绘制时的表现?
我已将此作为错误报告发布给 Oracle。我会在 link.
出现任何细节(被接受或拒绝)时更新此答案几个 similar bugs 已经发布了 "Cannot reproduce" 作为解决方案,但是它们不涉及虚拟机,只涉及 RDP 会话(我无法通过 RDPing 到我的工作桌面,而不是虚拟机)。
我确实找到了解决方法 - 显然从 D3D 堆栈切换并强制使用 OpenGL 堆栈(启动时的 -Dsun.java2d.d3d=false
选项)可以防止这种情况发生。我现在添加了一些代码来检查应用程序是否在 VM 上启动并相应地设置选项。
编辑
错误报告已被接受,但目前在 "Cannot reproduce" 中。 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8191018