在 Swing 应用程序启动期间,首次调用 JFrame 构造函数需要很长时间(因为 java.awt.Window())
我正在尝试使用Java Swing构建一个简单,轻量级且响应迅速的应用程序。但是,当它启动时,在窗口(JFrame)出现之前有一个明显的延迟(>500ms)。
我已经把它追溯到java.awt.Window类的构造函数,它是JFrame的祖先。
奇怪的是,构造函数仅在第一次调用时速度较慢。如果我创建多个 JFrame 对象,则第一个对象在构造函数中花费的时间约为 600 毫秒,但对于后续对象,通常测量为 0 毫秒。
下面是一个简单的示例,在我的系统上,它显示了第一个构造函数调用的显著延迟,而不是第二个构造函数调用:
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
long start;
start = System.currentTimeMillis();
JFrame frame1 = new JFrame();
System.out.println((System.currentTimeMillis() - start) + " for first JFrame.");
start = System.currentTimeMillis();
JFrame frame2 = new JFrame();
System.out.println((System.currentTimeMillis() - start) + " for second JFrame.");
}
});
}
典型输出:
641 for first JFrame.
0 for second JFrame.
如果我在JFrame对象之前添加这个窗口对象初始化:
java.awt.Window window = new java.awt.Window(null);
然后,输出将更改为如下所示的内容:
578 for first Window.
47 for first JFrame.
0 for second JFrame.
当我尝试使用 Window 的超类 java.awt.Container 时,Window 构造函数仍然是需要很长时间才能执行的构造函数(因此问题不会超出 Window 类)。
由于 JFrame 构造函数调用 Window 构造函数,因此上述内容似乎表明对 Window 构造函数的第一次调用开销很大。
在对构造函数的第一次调用中发生了什么,这需要这么长时间,我能做些什么吗?是否有一些简单的解决方案,或者该问题是 Swing/AWT 的根本问题?或者它可能是特定于我的系统/设置的问题?
我希望我的应用程序打开的速度与MS记事本一样快(或几乎一样快),并且,虽然我可以在记事本打开时将文本打印到控制台(如果我在第一个JFrame初始化之前放置代码),但上述问题意味着在窗口可见之前几乎有整整一秒钟的延迟。我是否需要使用其他语言或 GUI 框架才能获得我想要的性能?
编辑:如果我添加 Thread.sleep(10000) 作为 run() 的第一行,结果不会改变(它们只是在 10 秒后出现)。这表明问题不是由某些异步启动代码引起的,而是由构造函数调用直接触发的。
编辑 2:实现 NetBeans Profiler 可以在 JRE 类内部进行剖析,并发现大部分时间都花在初始化 sun.java2d.d3d.D3DGraphicsDevice 对象(Window 对象需要屏幕边界和插图)上,该对象是 Java 6u10 中引入的“Microsoft Windows 平台的 Direct3D 加速渲染管道,默认启用”的一部分。.可以通过将“-Dsun.java2d.d3d=false”属性传递给JVM来禁用它,这确实将启动时间缩短了大约3/4,但我还不确定我是否需要它(D3D),或者是否有其他方法可以更快地加载它。如果我将该参数放在命令行上,则输出如下:
0 for first Window
47 for first JFrame.
0 for second JFrame.
我会回来清理这篇文章,我以后再深入挖掘。