我最近注意到在运行Java应用程序时常见的延迟峰值。延迟峰值大约每10-15秒出现一次,持续时间为1-5秒。我想可能是因为我创造了很多过程。因此,我创建了一个简单的Java应用程序,它只创建了一个窗口:
public class Main extends Canvas {
private static final long serialVersionUID = 1L;
public JFrame frame = new JFrame();
public Main() {
frame.add(this);
frame.setSize(1000, 750);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
new Thread(() -> run()).start();
}
public void run() {
boolean running = true;
while(running) {
BufferStrategy bs = getBufferStrategy();
if(bs != null) {
Graphics g = bs.getDrawGraphics();
render(g);
g.dispose();
bs.show();
} else {
createBufferStrategy(3);
}
}
}
public void render(Graphics g) {
g.setColor(Color.green);
g.fillRect(0, 0, getWidth(), getHeight());
}
public static void main(String[] args) {
new Main();
}
}
当我运行它时,GPU使用率从0-3%一直到95-100%。如果我不创建线程(在Main()的末尾),GPU根本不会受到影响,但现在我无法在窗口上渲染任何东西。我认为这与BufferStrategy有关,但我不确定。我的GPU是NVIDIA GeForce GTX 1660 Ti,我的操作系统是Windows 10 Home。所以我的问题是:为什么GPU的使用率如此之高,我该如何解决这个问题?
看起来while(running)
做了太多的调用,因为它将运行到系统的最大容量(可能超过60 FPS !)
也许你应该通过某种计时器每60帧调用一次,而不是使用"残酷的"。While循环?看起来这可能是您的问题的答案:如何设置具有刷新率的JFrame ?
这从根本上误解了swing中的JFrame应该如何工作。通过使用swing,您可以让操作系统(和VM)处理交互和呈现。根本不需要手动渲染线程。
相反,你应该重写paintComponent
函数并使用该图形对象来进行渲染(不要忘记调用super函数来渲染其他位)。当需要绘制图形时,系统将调用该函数。
这样做的唯一方式是当你试图手动渲染视频到JFrame时。但即便如此,最好的方法还是使用现有的组件库来为您处理它。