13

Before going frustrated about the title, I would like to clear out that I am a fresher on JavaFX UI. I have been a developer for 9 years, using Swing and currently I decided to give a try to the JavaFX. Examples on the net shows that JavaFX really can create beautiful GUIs compared to Swing. Maybe I am trying to create and deploy GUIs the wrong way, but one thing is for sure. JavaFX panes load slower than Swing and consumes a lot more memory. The same GUI was redesigned with JAVAFX and it takes almost 200Mb while the Swing GUI take only 50Mb.

Here I give an example of the code of how I create the GUIs programmatically using FXML.

public class PanelCreator {

   private FXMLPane<LoginPaneController>           loginFXML;
   private FXMLPane<RegistrationPaneController>    registerFXML;
   private FXMLPane<EmailValidationPaneController> emailValidationFXML;

   public PanelCreator() {
      this.rootPane = rootPane;
      try {
        loginFXML           = new FXMLPane<LoginPaneController>("Login.fxml");
        registerFXML        = new FXMLPane<RegistrationPaneController>("Register.fxml");
        emailValidationFXML = new FXMLPane<EmailValidationPaneController>("EmailValidation.fxml");
      } catch (IOException e) {e.printStackTrace();} // catch
   } // Constructor Method

   public Pane getLoginPane() {
      return loginFXML.getPane();
   } // getLoginPane()

   public Pane getRegisterPane() {
      return registerFXML.getPane();
   } // getRegisterPane

   public Pane getEmailValidationPane() {
      return emailValidationFXML.getPane();
   } // getEmailValidationPane

   public LoginPaneController getLoginPaneController() {
      return loginFXML.getController();
   } // getLoginPaneController()

   public RegistrationPaneController getRegistrationPaneController() {
      return registerFXML.getController();
   } // getRegistrationPaneController()
} // class PanelCreator

The constructor method of PanelCreator creates 3 FXMLPane classes, a class that combines both the FXML Pane and its Controller. An code of FXMLPane class is shown on the following code.

public class FXMLPane<T> {

    private Pane pane;
    private T paneController;

    public FXMLPane(String url) throws IOException {
        URL location = getClass().getResource(url);
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(location);
        fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
        pane = fxmlLoader.load(location.openStream());
        paneController = fxmlLoader.<T>getController();
    } // Constructor Method

    public Pane getPane() {
        return pane;
    } // getPane()

    public T getController() {
        return paneController;
    } // getController()
}

Through PanelCreator now I can use the get methods to get each JavaFX Panel and its controller and I do not have to run the FXML load method every time to get the panel. Currently, what bothers me is not that the creation of FXML GUIs is slower than Swing but more that the RAM is 3x and 4x times more than the correspoing Swing version.

Can someone explain to me what I am doing wrong? The FXML files have just basic components on a Grid Pane, components like buttons, layers and textfields.

Memory Consumption Between Java and JavaFX

The code for the above example can be found here

javasuns
  • 1,061
  • 2
  • 11
  • 22
  • Did you check that the heap is really consumed? Java consume native memory if it needed it as sometime but never returns that to the OS (because it is better from a performance point of view). So did you try to print how much heap is left? – tomsontom Mar 04 '15 at 19:29
  • How are you measuring memory consumption? Can you provide a simple sample application for somebody else to profile? Are you running your comparable Swing and JavaFX applications on exactly the same hardware, the same Java runtime version and with the same command line switches? – jewelsea Mar 04 '15 at 23:44
  • Truly understanding the memory consumption behavior of an application can be a tricky and difficult thing. From the code and information you have provided thus far, it is not possible for somebody else to understand and diagnose the memory consumption of your application nor to concretely determine what you may be doing wrong. – jewelsea Mar 04 '15 at 23:48
  • I have updated this thread with a screenshot and the resource for downloading the code I have developed. – javasuns Mar 05 '15 at 08:39
  • 1
    Yeh, I see what you mean. Using Java 8u40 on my PC, the Swing version uses about 30MB and FX uses about 70MB. It appears then that FX is a heavier toolkit. Ten years ago that would have worried me too but today with even cellphones having GB of RAM it shouldn't be an issue, I think? Consider also that FX has features/abilities that Swing doesn't have which would make it heavier. – Jurgen Mar 05 '15 at 10:17
  • @Jurgen Yes I can agree with you that JavaFX includes more features and therefore is heavier, but I have not used any of those. I am just creating simple panes here. Imagine, that the full application will have to load more panes, and even sub-panes with results into the main pains; something that will lead to great memory consumption. It seems that for every pane created, around 30mb are consumed which is not reasonable. – javasuns Mar 05 '15 at 10:21
  • In my app its works out to about 12MB per pane, **including data**. I'm developing a patient management system .... I opened 5 patients each with 10 tabs containing complex sub-panes (text fields, text areas, lists, tables, trees, web view, etc). The framework is about 5 panes and it all added up to about 650MB. – Jurgen Mar 05 '15 at 11:30
  • @Jurgen That's way too much:) it will take half of the available memory on a regular cell phone. Can you do a quick test, by creating a similar UI with Java(not JavaFX) to make a comparison? – javasuns Mar 05 '15 at 11:32
  • No, I developed this from scratch - there's no previous Swing version. Also its a desktop app, developing for cell phone would be different. For instance the 5 patients were all open at the same time! If I only allowed one at a time then I'd only need say 200MB constantly. – Jurgen Mar 05 '15 at 11:43
  • Well even firefox that is the most heavy app used so far does not take so much memory. Something goes really wrong here – javasuns Mar 05 '15 at 11:47
  • I agree that it would be really really nice if FX's memory consumption could be reduced :-) – Jurgen Mar 05 '15 at 12:02
  • Using the raw process memory usage reports from the Windows Activity Monitor is not a great way to measure the memory usage efficiency of an application. For example, if the machine has unused memory, it is sometimes more efficient for a process to grab some of that memory, even when it doesn't need it, because the process might be able to offer better execution process with the extra memory now or in the future (e.g. less thrashing of the garbage collector in a JVM. – jewelsea Mar 05 '15 at 22:39
  • 4
    I ran your apps restricting the maximum heap memory size to a minimum size which allowed the application to start up - on OS X Java 8u40, for the Swing program this was 4Mb `java -Xmx4m`, for the JavaFX program, this was 8Mb `java -Xmx8m`. So both the Swing and JavaFX programs are able to operate with a fairly small java heap space usage. – jewelsea Mar 05 '15 at 22:46
  • If you run your applications with default java command line settings through a tool like [VisualVM](https://visualvm.java.net) and use the tool to trigger a garbage collection, you will find that both programs only use a few megabytes of heap space and the majority of the heap memory allocated to the Java process is unused. – jewelsea Mar 05 '15 at 22:48
  • @jewelsea so is there a way to always avoid the extra memory consumption and make the application run only with the actual minimum memory needed? – javasuns Mar 06 '15 at 05:28
  • You could set the maximum heap size explicitly at the command line as demonstrated in one of my previous comments. Be careful doing so, because it limits the memory available to your application. If you set the limit too low, your application will run out of memory, it also might not perform as well as it needs to run garbage collection more often. You can google topics on Java memory consumption to find more information. – jewelsea Mar 06 '15 at 18:52

1 Answers1

16

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.

Zomono
  • 772
  • 6
  • 17
  • 2
    !!! - the revelation that one can get the JVM to actually scale back the memory it has reserved from th OS is is a breakthrough, for me at least. The other behavior has long since been a major major detractor for Java for me. Any targeted links to text that specifically talks about achieving that behavior? – naki Apr 18 '17 at 20:43
  • 2
    I found the following summary writeup helpful: http://www.stefankrause.net/wp/?p=14 . With such configurations, I won't have to avoid using JVM based tools so much. – naki Apr 18 '17 at 21:12
  • @naki I've just tested that using --XX:+UseG1GC. When I manually GC, I see the same thing as the chart above shows, but according to the OS (by watching top or MacOS Activity Monitor) the app was still consuming the same thing as before (around 200MB in my case, while visualVM says the allocated heap is only around 63MB). I am testing with Java 8, will check later with Java 14 to see if things are better. – Renato Apr 06 '20 at 11:41