Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

First call to JFrame constructor takes a long time during Swing application startup (because of java.awt.Window())

I'm trying to build a simple, lightweight, and responsive application using Java Swing. When it launches, however, there is a noticeable delay (>500ms) before the window (a JFrame) appears.

I've tracked it down to the constructor of the java.awt.Window class, which is an ancestor of JFrame.

Oddly, the constructor is only slow for the first call. If I create multiple JFrame objects, the time spent in the constructor is ~600ms for the first object, but is typically measured as 0ms for subsequent objects.

Here's a simple example which, on my system, shows this significant delay for the first constructor call but not the second:

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.");
        }
    });
}

With typical output:

641 for first JFrame.
0 for second JFrame.

If I add this Window object initialization before the JFrame objects:

java.awt.Window window = new java.awt.Window(null);

Then the output changes to something like:

578 for first Window.
47 for first JFrame.
0 for second JFrame.

When I try the same with the superclass of Window, java.awt.Container, the Window constructor is still the one that takes a long time to execute (so the problem doesn't go above the Window class).

Since the JFrame constructor calls the Window constructor, the above seems to indicate that the first call to the Window constructor is expensive.

What happens in the first call to the constructor that takes so long, and is there anything I can do about it? Is there some simple fix or is the problem fundamental to Swing/AWT? Or is it perhaps a problem specific to my system/setup?

I'd like my application to open as fast (or nearly as fast) as MS Notepad, and, while I can have text printed to the console around the time Notepad opens (if I put the code before the first JFrame initialization), the above problem means that there is almost a whole second of delay before the window is visible. Will I need to use a different language or GUI framework to get the performance I'm after?


Edit: If I add Thread.sleep(10000) as the first line of run(), the results don't change (they just appear 10 seconds later). This suggests that the problem is not caused by some asynchronous startup code but is instead triggered directly by the constructor call.

Edit 2: Realized the NetBeans Profiler can profile inside the JRE classes, and discovered that most of the time is spent initializing a sun.java2d.d3d.D3DGraphicsDevice object (the Window object needs screen bounds and insets), which is part of a "Direct3D Accelerated Rendering Pipeline for Microsoft Windows Platforms, Enabled by Default", introduced in Java 6u10. It can be disabled by passing the "-Dsun.java2d.d3d=false" property to the JVM, which does reduce the startup time by about 3/4, but I'm not yet sure if I'll need it (D3D) or if there's some other way to get it to load faster. Here is the output if I put that parameter on the command line:

0 for first Window
47 for first JFrame.
0 for second JFrame.

I'll come back and clean this post up after I dig deeper later.

like image 596
A Coder Avatar asked Aug 08 '11 05:08

A Coder


People also ask

Is awt faster than Swing?

The execution time of AWT is more than Swing. The execution time of Swing is less than AWT. 5. The components of Java AWT are platform dependent.

Is JFrame awt or Swing?

Class JFrame. An extended version of java. awt. Frame that adds support for the JFC/Swing component architecture.

What is Swing explain JFrame in Java?

swing. JFrame class is a type of container which inherits the java. awt. Frame class. JFrame works like the main window where components like labels, buttons, textfields are added to create a GUI.

Which method will call JFrame to get displayed?

We can implement most of the java swing applications using JFrame. By default, a JFrame can be displayed at the top-left position of a screen. We can display the center position of JFrame using the setLocationRelativeTo() method of Window class.


3 Answers

This answer records what I have found so far. If anyone has more information, please comment or post an answer. I am not completely satisfied with simply disabling Swing's use of D3D, and am open to other solutions.

The Cause: D3D Initialization

Swing uses the Java2D API for drawing, and according to this Java SE 7 troubleshooting guide, Java2D uses a set of rendering pipelines, "which can be roughly defined as different ways of rendering the primitives". More specifically, a Java2D rendering pipeline seems to connect cross-platform Java code to native graphics libraries (OpenGL, X11, D3D, DirectDraw, GDI) that may support hardware acceleration.

In Java 1.6.0_10 (aka 6u10), a "fully hardware accelerated graphics pipeline" based on Direct3D was added to Java2D for Windows to improve rendering performance in Swing and Java2D applications (enabled by default).

By default, when Java2D is used on a Windows system, both this Direct3D pipeline and a DirectDraw/GDI pipeline are enabled by default (I assume they are each being used for different things).

The D3D library, at least, is only loaded and initialized when needed, and a native D3D initialization function which gets called the first time a Window (or a Window descendant) is constructed takes ~500ms (for me) and causes the reported slowness of initialization, and disabling the D3D pipeline seems to remove the call to this native function, significantly decreasing startup time. (Although I'd much prefer to delay, precompute, share (across different java apps), or optimize the D3D initialization, and I wonder if it's this slow for other languages.)

Granted, it's possible that on most systems the time spent in D3D init is negligible, and it is only a problem on my system due to some hardware or driver problem, but I'm somewhat skeptical of this (although, if true, that would be an easy fix).


Detailing the trace down to the native initD3D()

In more detail (skip the following paragraph if you don't care), I used the Netbeans profiler and debugger to find that:

When a JFrame is initialized (constructor called), the constructor of ancestor class java.awt.Window gets called. The Window initializes its GraphicsConfiguration device, which tries to retrieve the default screen device, and so on. The first time this happens (when the first Window or Window descendant is initialized), the screen device doesn't exist, so it is built. In this process, the sun.java2D.d3d.D3DGraphicsDevice class gets initialized, and in its static initialization block (see <clinit>()) it calls a native function, initD3D(), which takes a significant time to execute (~500ms).

I was able to find a version of the source code for D3DGraphicsDevice and its static init block (and I'm really just assuming from this source that initD3D() is what makes its <clinit>() take so long - my profiler doesn't seem to acknowledge native functions - but it's a reasonable guess).


One workaround - disable D3D for Java2D

The D3D pipeline can be disabled by running java with the -Dsun.java2d.d3d=false option, as per this guide on Java2D "system properties" (and also the aforementioned troubleshooting guide). I think this disables D3D but not DirectDraw, which can be disabled with Dsun.java2d.noddraw=true (and then "all operations will be performed with GDI"), but this doesn't noticeably improve initialization time.

For example, I might use a command like the following to run MyJar.jar without D3D:

java -jar -Dsun.java2d.d3d=false MyJar.jar

With the code posted in the question (which initializes a Window and then 2 JFrame objects), I get results like this:

0 for first Window
47 for first JFrame.
0 for second JFrame.

Instead of results like this:

547 for first Window
31 for first JFrame.
0 for second JFrame.

(Note that time is in milliseconds and is measured with System.currentTimeMillis() on Windows, which I think has a resolution of around 15 to 16 ms.)


OpenGL vs Direct3D

OpenGL is used instead of Direct3D if the -Dsun.java2d.opengl=True option is used. On my system there is a slight improvement (~400ms for OpenGL vs ~500ms for D3D), but the delay is still noticeable.


Other Delays

I noticed that initialization of the first JFrame object, even if it is not the first Window, takes much more time than the initialization of subsequent JFrame objects (recorded as 31 to 47 ms vs 0ms).

Profiling indicates this is related to the creation of the first glass pane (a JPanel), and ultimately seems to be caused by Look and Feel and system property intialization/loading inside the javax.swing.UIManager class and object initialization code. It's not too important, but it does explain the observed anomaly.

In my actual program which is a bit more complicated (has to initialize more Swing components), delays seem to be more diffusely distributed in the Swing code, but I've noticed a significant amount of native class loading, "UI installing" (loading default UI properties, etc.), and such. Unfortunately, I don't think there's much to be done about these (please speak up if there is).


Closing thoughts

In the end, there's only so much that can be done, and I have to recognize how far Swing and the JVM have come in the past years.

like image 108
A Coder Avatar answered Nov 03 '22 09:11

A Coder


The creation of the first jframe involves loading the swing library. JVM doesn't load the library looking at the import statement. The libraries are loaded only when the first call to that library is made.

In this case frame1 creation is the first statement that calls the Swing library. By the time frame2 instance is created the swing libraries are already loaded and hence the object creation for frame2 is too fast even to notice some lapse of time. Hence it shows 0.

This explains why it shows 578, 47, 0 when you add up Window statement above the two. This is because the first statement takes time to load java.awt library. Second takes time to load the swing library. And the thirds shows 0 as the library needed for its creation is already loaded.

You can even test it this way. Try to replace the second JFrame creation with JPanel and it still it shows 0.

like image 42
Vamsi Emani Avatar answered Nov 03 '22 09:11

Vamsi Emani


My guess is that it's loading native libraries. If this is the case, there is not much you can do about it.

like image 34
Maurice Perry Avatar answered Nov 03 '22 09:11

Maurice Perry