Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8253229

JavaFX abnormally slow

XMLWordPrintable

    • x86_64
    • windows_7

      ADDITIONAL SYSTEM INFORMATION :
      I have tested the samples with Java 8 and Java 10.

      A DESCRIPTION OF THE PROBLEM :
      When the scene contains a lot of nodes, changing the scene graph takes a long time.
      The sample code in JavaFX is about 20 times slower than the equivalent sample in Swing.
      Everything is slow in JavaFX : scrolling, changing the widow size, changing the spilt pane size...
      The memory footprint is also huge compared to Swing.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the two sample applications and click several times on the "Show / Hide properties form" toggle button. The time to open or close the properties form is displayed next to the button.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      I expect JavaFX to be at least as fast as Swing.

      ACTUAL -
      The JavaFX sample shows a time of about 3000 to 4000 ms.
      The Swing sample shows a time less than 200 ms.
      JavaFX in this use case is 20 times slower than Swing which is abnormal.

      ---------- BEGIN SOURCE ----------
      This is JavaFX sample :
      --------------------------------------------------------------------------------------------------------------
      import java.util.ArrayList;
      import java.util.List;

      import javafx.application.Application;
      import javafx.application.Platform;
      import javafx.scene.Scene;
      import javafx.scene.control.Label;
      import javafx.scene.control.ScrollPane;
      import javafx.scene.control.SplitPane;
      import javafx.scene.control.ToggleButton;
      import javafx.scene.control.ToolBar;
      import javafx.scene.control.Tooltip;
      import javafx.scene.layout.BorderPane;
      import javafx.scene.layout.GridPane;
      import javafx.scene.layout.HBox;
      import javafx.scene.layout.VBox;
      import javafx.stage.Stage;

      /**
       * Application demonstrating JavaFX slowness to toggle between a main form and a split pane containing the main form and a properties form.
       * The time can be compared to the equivalent {@link FastSwingDemo Swing demo}.
       */
      public final class SlowJavaFXDemo extends Application {

      private static final int COMPLEXITY = 50;

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

      @Override
      public void start(Stage stage) {
      stage.setScene(createScene());
      stage.setTitle("Slow JavaFX Demo");
      stage.setWidth(800);
      stage.setHeight(600);
      stage.setOnCloseRequest(event -> Platform.exit());
      stage.show();
      }

      private static Scene createScene() {
      final VBox content = new VBox();
      final ScrollPane mainForm = new ScrollPane(content);
      final BorderPane mainPane = new BorderPane(mainForm);

      final Label executionTime = new Label();

      final ToggleButton togglePropertiesForm = new ToggleButton("Show / Hide properties form");
      togglePropertiesForm.selectedProperty().addListener((observable, wasSelected, isSelected) -> {
      final long start = System.currentTimeMillis();
      if (isSelected) {
      final SplitPane splitPane = new SplitPane(mainForm, new Label("Very simple properties form"));
      mainPane.setCenter(splitPane);
      executionTime.setText("Properties form opened in ");
      } else {
      mainPane.setCenter(mainForm);
      executionTime.setText("Properties form closed in ");
      }
      Platform.runLater(() -> executionTime.setText(executionTime.getText() + (System.currentTimeMillis() - start) + " ms"));
      });

      final ToolBar toolBar = new ToolBar(togglePropertiesForm, executionTime);

      content.getChildren().addAll(toolBar, createGridPane());

      return new Scene(mainPane);
      }

      private static GridPane createGridPane() {
      final VBox innerBox = new VBox();
      innerBox.getChildren().addAll(createOuterBoxes());

      final GridPane gridPane = new GridPane();
      gridPane.setHgap(5);
      gridPane.add(innerBox, 0, 0);
      gridPane.add(new VBox(), 0, 1);
      return gridPane;
      }

      private static List<OuterBox> createOuterBoxes() {
      final List<OuterBox> outerBoxes = new ArrayList<>();
      for (int i = 0; i < COMPLEXITY; i++) {
      final OuterBox box = new OuterBox();
      outerBoxes.add(box);
      for (int j = 0; j < COMPLEXITY; j++) {
      box.addInnerBox(new InnerBox());
      }
      }
      return outerBoxes;
      }

      private static class OuterBox extends VBox {

      private OuterBox() {
      final Label label1 = new Label("Label1");
      final Label label2 = new Label("Label2");
      this.getChildren().addAll(label1, label2);
      }

      private void addInnerBox(InnerBox box) {
      getChildren().add(box);
      }
      }

      private static class InnerBox extends HBox {

      private InnerBox() {
      for (int i = 0; i < 10; i++) {
      final Label label = new Label("Label[" + i + "]");
      label.setTooltip(new Tooltip("Tooltip"));
      this.getChildren().add(label);
      }
      }
      }
      }
      --------------------------------------------------------------------------------------------------------------

      This is Swing sample :
      --------------------------------------------------------------------------------------------------------------
      import java.awt.BorderLayout;
      import java.awt.Container;
      import java.awt.GridLayout;
      import java.util.ArrayList;
      import java.util.List;

      import javax.swing.Box;
      import javax.swing.BoxLayout;
      import javax.swing.JFrame;
      import javax.swing.JLabel;
      import javax.swing.JPanel;
      import javax.swing.JScrollPane;
      import javax.swing.JSplitPane;
      import javax.swing.JToggleButton;
      import javax.swing.JToolBar;
      import javax.swing.SwingUtilities;
      import javax.swing.WindowConstants;

      /**
       * Application demonstrating Swing fastness to toggle between a main form and a split pane containing the main form and a properties form.
       * The time can be compared to the equivalent {@link SlowJavaFXDemo JavaFX demo}.
       */
      public final class FastSwingDemo {

      private static final int COMPLEXITY = 50;

      public static void main(String[] args) {
      SwingUtilities.invokeLater(() -> {
      final JFrame frame = new JFrame("Fast Swing Demo");
      buildRoot(frame.getContentPane());
      frame.setSize(800, 600);
      frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      frame.setVisible(true);
      });
      }

      private static void buildRoot(final Container borderPane) {
      final Box content = new Box(BoxLayout.Y_AXIS);
      final JScrollPane mainForm = new JScrollPane(content);
      final JPanel mainPane = new JPanel(new BorderLayout());
      mainPane.add(mainForm, BorderLayout.CENTER);

      final JLabel executionTime = new JLabel();

      final JToggleButton togglePropertiesForm = new JToggleButton("Show / Hide properties form");
      togglePropertiesForm.addActionListener(actionEvent -> {
      final long start = System.currentTimeMillis();
      if (togglePropertiesForm.isSelected()) {
      final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mainForm, new JLabel("Very simple properties form"));
      mainPane.removeAll();
      mainPane.add(splitPane, BorderLayout.CENTER);
      mainPane.revalidate();
      executionTime.setText("Properties form opened in ");
      } else {
      mainPane.removeAll();
      mainPane.add(mainForm, BorderLayout.CENTER);
      mainPane.revalidate();
      executionTime.setText("Properties form closed in ");
      }
      SwingUtilities.invokeLater(() -> executionTime.setText(executionTime.getText() + (System.currentTimeMillis() - start) + " ms"));
      });

      final JToolBar toolBar = new JToolBar();
      toolBar.add(togglePropertiesForm);
      toolBar.add(executionTime);

      content.add(toolBar);
      content.add(createGridPane());

      borderPane.add(mainPane, BorderLayout.CENTER);
      }

      private static JPanel createGridPane() {
      final Box innerBox = new Box(BoxLayout.Y_AXIS);
      createOuterBoxes().forEach(innerBox::add);
      innerBox.validate();

      final GridLayout gridLayout = new GridLayout(0, 2);
      gridLayout.setHgap(5);

      final JPanel gridPane = new JPanel();
      gridPane.add(innerBox);
      gridPane.add(new Box(BoxLayout.Y_AXIS));
      return gridPane;
      }

      private static List<OuterBox> createOuterBoxes() {
      final List<OuterBox> outerBoxes = new ArrayList<>();
      for (int i = 0; i < COMPLEXITY; i++) {
      final OuterBox box = new OuterBox();
      outerBoxes.add(box);
      for (int j = 0; j < COMPLEXITY; j++) {
      box.addInnerBox(new InnerBox());
      }
      }
      return outerBoxes;
      }

      private static class OuterBox extends Box {

      private OuterBox() {
      super(BoxLayout.Y_AXIS);
      final JLabel label1 = new JLabel("Label1");
      final JLabel label2 = new JLabel("Label2");
      this.add(label1);
      this.add(label2);
      }

      private void addInnerBox(InnerBox box) {
      this.add(box);
      }
      }

      private static class InnerBox extends Box {

      private InnerBox() {
      super(BoxLayout.X_AXIS);
      for (int i = 0; i < 10; i++) {
      final JLabel label = new JLabel("Label[" + i + "]");
      label.setToolTipText("Tooltip");
      this.add(label);
      }
      }
      }
      }
      --------------------------------------------------------------------------------------------------------------
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      No workaround found.

      FREQUENCY : always


            kcr Kevin Rushforth
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: