You are on page 1of 36

Swing Performance

GUI at the speed of light

copyright 2009 trainologic LTD

Swing Performance

Common Misconceptions. Pitfalls. Best Practices.

copyright 2009 trainologic LTD

Swing Performance

Misconceptions
The greatest misconception regarding Swing
performance is that it is poor.

Swing is a very fast UI framework, it is us developers


who are making mistakes that makes Swing performance look bad.

In general, if you follow the guidelines given


throughout this course your GUI should perform well.

3
copyright 2009 trainologic LTD

Swing Performance

Misconceptions
Swing is using sophisticated technics to make sure its
performance is good.

It is employing double buffering using off-screen


images.

It uses VolatileImages to take advantage of graphics


accelerators.

And it makes sure to always update only necessary


parts of the UI which are visible to the user.

All these make sure Swing performs well as long as we


treat it nicely.
4
copyright 2009 trainologic LTD

Swing Performance

Misconceptions
The main problem of Swing is its complexity, not its
performance.

Swings complex design makes it very flexible, but at


the same time makes it really easy to make mistakes that affect performance and maintainability.

5
copyright 2009 trainologic LTD

Swing Performance

Misconceptions
Another misconception is the mix-up between
performance and perceived performance.

One might have a GUI that performs operations very


fast, but the users would feel that the performance is awful.

How is that possible?

6
copyright 2009 trainologic LTD

Swing Performance

Misconceptions
As users, we are very sensitive to responsive GUI. As long as we feel something is happening, we are
willing to wait.

But as soon as we feel something is stuck, even for one


second, we feel the GUI performance is bad.

Writing an irresponsive GUI will lead users to believe it


is a badly performing GUI.

7
copyright 2009 trainologic LTD

Swing Performance

Common Misconceptions. Pitfalls. Best Practices.

copyright 2009 trainologic LTD

Swing Performance

Cell Renderers
Cell renderers are a great way to implement
sophisticated cells in components like JTable and JTree.

A common pitfall is forgetting that a renderer is nothing


but a rubber stamp.

The renderer is supposed to return a component that is


painted on the screen in the cells position.

This component should be reused to paint many cells. Cell renderers that create a new component every time
a cell is painted hinder performance.
9
copyright 2009 trainologic LTD

Swing Performance

Cell Renderers
Renderers are used very often by the component. They are invoked every time a single cell needs to be
painted.

Creating a new component each time they are invoked


not only wastes time in the rendering, but also creates a lot of garbage to be collected.

10
copyright 2009 trainologic LTD

Swing Performance

Garbage Collection
As you know, memory in Java is managed using a
garbage collection mechanism.

The problem with garbage collection is that when it


runs it stops all other threads. This is called the stop the world approach.

This means that each time the garbage collector is


running, the GUI freezes.

11
copyright 2009 trainologic LTD

Swing Performance

Garbage Collection
Long garbage collections are very bad for Swing
applications.

Swing is doing its best to avoid creating unnecessary


garbage and is in most cases doing a good job.

Creating temporary objects in model methods that are


invoked often, can create loads of garbage and affect performance.

12
copyright 2009 trainologic LTD

Swing Performance

Threading
EDT is the thread making all GUI updates. Performing operations which are over several
milliseconds long makes the user feel the GUI is stuck.

13
copyright 2009 trainologic LTD

Swing Performance

Synchronized Models
Synchronization affects the performance even in a
single threaded environment.

The special threading model of Swing makes


synchronization completely unnecessary in Swing components and model.

Since model methods are invoked very often, anything


that makes them slower is bad.

14
copyright 2009 trainologic LTD

Swing Performance

Unnecessary invocation of revalidate()


revalidate() makes containers layout their components,
and in turn they must be repainted.

This method should be invoked only when something


that affects size and/or location has changed.

Invoking revalidate() often might have a great effect on


performance.

15
copyright 2009 trainologic LTD

Swing Performance

Common Misconceptions. Pitfalls. Best Practices.

copyright 2009 trainologic LTD

Swing Performance

Best Practices
Swing is a pure Java framework. This means, best practices of Java performance applies
for Swing.

Most of the best practices in this section are general


Java best practices.

Some of them are more important in Swing due to its


single-threaded nature.

17
copyright 2009 trainologic LTD

Swing Performance

String Handling
Never use String for string manipulations! Always use StringBuilder (there is rarely a need for
StringBuffer) for string manipulations.

If you want to work with characters, use a char[]! These are basic performance guidelines, and of course,
there is String.intern().

18
copyright 2009 trainologic LTD

Swing Performance

Comparing Strings
What is the output of the following code?
public static void main(String[] args) { String s1 = "Trainologic"; String s2 = "Trainologic"; System.out.println(s1 == s2); System.out.println(s1.equals(s2)); }

We got true and true. The first one may be surprising. It means that both s1
and s2 have the same address.

Lets take a look at the compiled byte-code


19
copyright 2009 trainologic LTD

Swing Performance

Looking at the Byte Code

As you can see, both s1 and s2 have the same


reference (#16) from the constant pool.

20
copyright 2009 trainologic LTD

Swing Performance

Comparing Strings cont.


What if we make a little change?
public static void main(String[] args) { String s1 = "Trainologic"; String s2 = new String("Trainologic"); System.out.println(s1 == s2); System.out.println(s1.equals(s2)); }

Now we got false and true. And that is ok. The new operator always creates a new
instance. So we end up with different addresses.

21
copyright 2009 trainologic LTD

Swing Performance

Comparing Strings cont.


And what do we get when we use intern()?
public static void main(String[] args) { String s1 = "Trainologic"; String s2 = new String("Trainologic"); System.out.println(s1 == s2); System.out.println(s1.equals(s2)); }

We get true and true. How can we explain that?!

22
copyright 2009 trainologic LTD

Swing Performance

intern()
The class String maintains a pool of strings. The intern() method will search for the current string in
the pool:

If found, a reference to the string from the pool will be returned. If it wasnt found, a new string will be created in the pool and its reference returned.

Thus, any two strings that have the same content, will
return the same reference on intern().
23
copyright 2009 trainologic LTD

Swing Performance

intern()
From performance point-of-view, the intern() method
can reduce your memory footprint (if you have a lot of identical string instances).

It may also improve comparison because == is faster


than equals().

Note that this is true only for strings that are different
and differ in a late character (the equals method first performs a == check).

A warning: it is very dangerous to use ==. If you


decide to use it, make sure that both sides were interned!
24
copyright 2009 trainologic LTD

Swing Performance

Exceptions
Exceptions are used with the try-catch-finally syntax. Lets see how it works and what are the performance
penalties regarding it.

Suppose we have the following method:


public void testEx(Person p) { try { p.setFirstName(null); } catch (IllegalArgumentException e) { // .. handle it } catch (NullPointerException e) { // .. handle it differently } }

25
copyright 2009 trainologic LTD

Swing Performance

Exceptions
Every method that treats exceptions (has catch
clauses) has an exception table associated with it:

26
copyright 2009 trainologic LTD

Swing Performance

Exceptions
At runtime, when an exception is thrown, the JVM will
consult the exception table to find the appropriate catch block.

It will do so by first looking for the code range and then


checking with instanceof for the appropriate exception type.

Clearly, you dont pay when exceptions are not thrown.

27
copyright 2009 trainologic LTD

Swing Performance

Exceptions
Whenever an instance of a descendant of Throwable is
created, a stacktrace snapshot is created as well.

This can put some pressure on both CPU & memory. Some flags can help you here:

-XX:+StackTraceInThrowable Whether stacktraces should be generated in Throwables (disabling it will make debugging impossible). -XX:MaxJavaStackTraceDepth=<value> Sets a threshold for the stacktrace depth.
28
copyright 2009 trainologic LTD

Swing Performance

Exceptions
As a rule, never use exceptions for flow-control. An example (without using exceptions).
public long iterateAllNoExceptions(List<Integer> coll) { long result = 0; // using regular iterator.hasNext() for (Integer element : coll) { result += element; } return result; }

29
copyright 2009 trainologic LTD

Swing Performance

Exceptions
Same example, now with exceptions:
public long iterateAllWithExceptions(List<Integer> coll) { long result = 0; int index = 0; // using exceptions for flow control try { while (true) { result += coll.get(index++); } } catch (IndexOutOfBoundsException e) { } return result; }

30
copyright 2009 trainologic LTD

Swing Performance

Exceptions
Benchmark: 1 million iterations

No Exceptions With Exceptions

31
copyright 2009 trainologic LTD

Swing Performance

Logging Level
Logging level affects performance significantly. Yep, you probably know this. Try to use logging level of Warning and up! It just happens all the time

32
copyright 2009 trainologic LTD

Swing Performance

Buffered Streams
When using InputStream & OutputStream, always wrap
them with their buffered counterparts.

Moreover, in most cases, arrays methods may yield


even greater performance.

Lets see an example

33
copyright 2009 trainologic LTD

Swing Performance

Buffered Streams
Note the three implementations:
inputStream = new FileInputStream(FROM_FILE); outputStream = new FileOutputStream(TO_FILE); while (true) { int b = inputStream.read(); if (b == -1) break; outputStream.write(bytedata); } inputStream = new BufferedInputStream(FileInputStream(FROM_FILE)); outputStream = new BufferedOutputStream(FileOutputStream(TO_FILE)); while (true) { int b = inputStream.read(); if (b == -1) break; outputStream.write(bytedata); } 34
copyright 2009 trainologic LTD

Swing Performance

Buffered Streams

inputStream = new FileInputStream(fileFrom); outputStream = new FileOutputStream(fileTo); int len = inputStream.available(); byte[] arr = new byte[len]; inputStream.read(arr); outputStream.write(arr);

35
copyright 2009 trainologic LTD

Swing Performance

Buffered Streams
Here is a benchmark of copying a 10M file with the 3
options:

Default Buffered Arrays

36
copyright 2009 trainologic LTD