Performance of Javafx Gui VS Swing

Performance of JavaFx Gui vs Swing

The Swing example flattens the image to 6002 = 360,000 pixels. In contrast, the JavaFX example strokes almost 2.4 million overlapping polygons when finally rendered. Note that your JavaFX example measures both the time to compose the fractal and the time to render it in the scene graph.

If you want to preserve the strokes comprising the fractal, compose the result in a Canvas, as shown here.

If a flat Image is sufficient, compose the result in a BufferedImage, convert it to a JavaFX Image, and display it in an ImageView, as shown below. The JavaFX result is over a second faster than the Swing example on my hardware.

Because SwingFXUtils.toFXImage makes a copy, a background Task<Image> could continue to update a single BufferedImage while publishing interim Image results via updateValue(). Alternatively, this MandelbrotSet features a Task that updates a WritableImage via its PixelWriter.

image

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
* @see https://stackoverflow.com/q/44136040/230513
*/
public class BufferedImageTest extends Application {

private static final int PANEL_WIDTH = 600, PANEL_HEIGHT = 600;
private static final int TRI_WIDTH = 500, TRI_HEIGHT = 500;
private static final int SIDE_GAP = (PANEL_WIDTH - TRI_WIDTH) / 2;
private static final int TOP_GAP = (PANEL_HEIGHT - TRI_HEIGHT) / 2;
private final int numberOfLevels = 13;
private int countTriangles;

@Override
public void start(Stage stage) {
stage.setTitle("BufferedImageTest");
StackPane root = new StackPane();
Scene scene = new Scene(root);
root.getChildren().add(new ImageView(createImage()));
stage.setScene(scene);
stage.show();
}

private Image createImage() {
BufferedImage bi = new BufferedImage(
PANEL_WIDTH, PANEL_HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setPaint(Color.white);
g.fillRect(0, 0, PANEL_WIDTH, PANEL_HEIGHT);
Point top = new Point(PANEL_WIDTH / 2, TOP_GAP);
Point left = new Point(SIDE_GAP, TOP_GAP + TRI_HEIGHT);
Point right = new Point(SIDE_GAP + TRI_WIDTH, TOP_GAP + TRI_HEIGHT);
g.setColor(Color.red);
long startTime = System.currentTimeMillis();
drawTriangle(g, numberOfLevels, top, left, right);
g.setPaint(Color.black);
g.drawString("Number of triangles: " + countTriangles, 15, 15);
g.drawString("Time : " + (System.currentTimeMillis() - startTime) + " ms", 15, 35);
g.drawString("Levels: " + numberOfLevels, 15, 50);
WritableImage image = SwingFXUtils.toFXImage(bi, null);
g.dispose();
return image;
}

private void drawTriangle(Graphics2D g, int levels, Point top, Point left, Point right) {
if (levels < 0) {
return;
}
countTriangles++;
Polygon tri = new Polygon();
tri.addPoint(top.x, top.y);
tri.addPoint(left.x, left.y);
tri.addPoint(right.x, right.y);
g.drawPolygon(tri);

// Get the midpoint on each edge in the triangle
Point p12 = midpoint(top, left);
Point p23 = midpoint(left, right);
Point p31 = midpoint(right, top);

// recurse on 3 triangular areas
drawTriangle(g, levels - 1, top, p12, p31);
drawTriangle(g, levels - 1, p12, left, p23);
drawTriangle(g, levels - 1, p31, p23, right);
}

private Point midpoint(Point p1, Point p2) {
return new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
}

public static void main(String[] args) {
launch(args);
}

}

Is JavaFX GUI heavy for the performance?

In the early days of JavaFX, I tried it out to show a large graph (thousands or tens of thousands of nodes and edges), and found that it was slow compared to displaying the same graph structure in Swing. However, most user interfaces are much simpler than what I was displaying, so any speed difference is irrelevant. Since those early days Oracle has put a lot of work into making JavaFX as fast as Swing. Today's performance in JavaFX is much closer to the performance of swing.

Here is a writeup of someone experience in switching from Swing to JavaFX:
http://www.oracle.com/technetwork/articles/java/casa-1919152.html

The author says:
Performance—Our overall impression is that JavaFX provides the same high level of performance as Swing when it comes to assembling and rendering screens with many components. And JavaFX provides much better performance in the area of transitions and animations (Swing provides very limited functionality in this area). Overall, performance is not an issue.

Swing vs JavaFx for desktop applications

What will be cleaner and easier to maintain?

All things being equal, probably JavaFX - the API is much more consistent across components. However, this depends much more on how the code is written rather than what library is used to write it.

And what will be faster to build from scratch?

Highly dependent on what you're building. Swing has more components around for it (3rd party as well as built in) and not all of them have made their way to the newer JavaFX platform yet, so there may be a certain amount of re-inventing the wheel if you need something a bit custom. On the other hand, if you want to do transitions / animations / video stuff then this is orders of magnitude easier in FX.

One other thing to bear in mind is (perhaps) look and feel. If you absolutely must have the default system look and feel, then JavaFX (at present) can't provide this. Not a big must have for me (I prefer the default FX look anyway) but I'm aware some policies mandate a restriction to system styles.

Personally, I see JavaFX as the "up and coming" UI library that's not quite there yet (but more than usable), and Swing as the borderline-legacy UI library that's fully featured and supported for the moment, but probably won't be so much in the years to come (and therefore chances are FX will overtake it at some point.)

JavaFX and Swing performance issues

This is not the answer that you are looking for, but since we have the same problem with Java 7 support, the answer is that Java 7 has reached its end of life:

July 2015: Updates for Java 7 are no longer available to the public.
Oracle offers updates to Java 7 only for customers who have purchased
Java support or have Oracle products that require Java 7.

https://www.java.com/en/download/faq/java_7.xml

There are no "good reasons" if problem solving is as easy as using a different java version. You don't break things by upgrading to Java 8.

Performance limitations of web vs desktop applications?

The user interface should only handle as much data as the user can handle. Can your users read a million data records per second? Probably not. So design the interaction between the user interface and the backend so that the UI only has to process the data the user can consume. You would apply techniques like lazy-loading and paging.

Browser based applications might still not be as fast as native applications, but for most purposes they are "fast enough." But you're not even comparing native to browser, you're comparing Java Swing to browser. In some benchmarks, the Chrome "V8" JavaScript execution engine beats Java. It's not at all clear if a Java Swing UI would be faster or slower than a ReactJS UI.

It is certainly not ideal to commit to a technology and discover months later that it's not going to work out. I would recommend you develop a quick throw-away prototype to get an idea of where the pain points may lie.

Swing and JavaFX concurrency

No, it is not officially possible currently. In both frameworks changes to the structure can only be done on the respective UI thread.

However, in the future this may change, but I do not know of any concrete plans that oracle may have and I cannot find an appropriate task in their jira.

edit: I found the specific thread about this on the javafx mailinglist:
http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-August/009541.html

jira issue: https://javafx-jira.kenai.com/browse/RT-30694

appearently there is an experimental system property that can be set to enable a "single threaded mode": -Djavafx.embed.singleThread=true

Multiple SwingNode Cause Extreme Performance Degradation

I submitted this as a bug. As of the time of writing, it's currently open and in the JDK backlog:

https://bugs.openjdk.java.net/browse/JDK-8144504

Unfortunately, while this bug is open, the only work-around seems to be to limit your Swing to JavaFX to Swing integration. We ended up remaking all of our Swing widgets that were being used in the JavaFX panel in JavaFX, which was a fairly substantial overhaul.

For the reference of anyone who wandered in here looking for a solution to this problem, I'm also going to post this JDK bug, which is also open as of the time of writing:

https://bugs.openjdk.java.net/browse/JDK-8136530

The bug states that, even if you only have one SwingNode in a JavaFX Pane in a JFXPanel, your CPU usage will dramatically increase (but the freezing of multiple nodes does not occur). This ended up biting us after we thought we cleverly got around the issue by limiting the number of SwingNode instances in our JavaFX Pane. Hopefully, this heads up will help prevent others from face-planting into it like we did.

EDIT (21/09/2017): The freezing bug is now listed as fixed with a fix version of Java 10. The CPU usage increase bug is still in an open state.

JavaFX eats my memory?

Summarizing the answers from the comment section:

  • JavaFX needs more memory in general. E.g. JavaFX uses double precision for all properties along the UI-components, while Swing uses integer values most of the time. But the difference should not be noticeable.
  • Java consumes more memory as it needs to. As a default Java does not return memory back to your system even if you trigger the garbage collection. Thus if a JavaFX program needs a lot of memory on the initialization process but frees it afterwards, the JRE continues to hold the maximum level of memory for ever (see picture 1). As a side effect the GC will be triggered less often, because there is so much free unused memory (see picture 2). You can change the default by using the JVM option -XX:+UseG1GC. This changes the behavior of how memory is allocated, how it's freed and when the GC is triggered. With this option the allocated memory should better fit in with the used memory. If you want more tuning see Java Heap Tuning
  • JavaFX is a new framework compared to Swing. It will be improved over time in performance and resources consumption. As you can see in picture 1 and 3 it has already been improved. It now uses 8 to 9MB of memory on a 64Bit Linux machine. This is even less memory than the Swing version. I used Oracle Java

    java version "1.8.0_111"
    Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
    Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)

Memory consumption over time for the JavaFX example program. It shows a huge amount of free memory compared to the used memory.

Picture 1: Memory consumption over time for the JavaFX example program. It shows a huge amount of free memory compared to the used memory. The GC was triggered manually multiple times to show used memory part without garbage.

Memory consumption over time for the JavaFX example program, but without manually triggering the GC.

Picture 2: Memory consumption over time for the JavaFX example program, but without manually triggering the GC. The used memory grows and grows because the GC isn't triggered.

Memory consumption over time for the JavaFX example program using the GC option -XX:+UseG1GC

Picture 3: Memory consumption over time for the JavaFX example program using the GC option -XX:+UseG1GC. After the first GC cycle the memory size was reduced to fit the real size of used memory.



Related Topics



Leave a reply



Submit