3

I have written a piece of code, to make letters appear and fly as I write them. The problem it consumes a lot of memory.

I already optimized it a little bit by

  • Sharing the path object and update its parameters in listeners.
  • Calling gc each time a new letter is printed

But it still uses a lot of memory, so any ideas about how to reduce its memory utilization ?

Thanks in advance.



    package sample;

    import javafx.animation.PathTransition;
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.Pane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.LineTo;
    import javafx.scene.shape.MoveTo;
    import javafx.scene.shape.Path;
    import javafx.scene.text.Font;
    import javafx.scene.text.Text;
    import javafx.stage.Stage;
    import javafx.util.Duration;

    public class Main extends Application {

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

        @Override
        public void start(Stage primaryStage) throws Exception {
            Pane root = new Pane();
            Scene scene = new Scene(root);
            root.setCache(false);
            primaryStage.setTitle("Hello World");
            primaryStage.setScene(scene);


            Path path = new Path();
            root.widthProperty().addListener((observableValue, oldSceneWidth, newSceneWidth) -> SetPathElements(path, root));
            root.heightProperty().addListener((observableValue, oldSceneWidth, newSceneWidth) -> SetPathElements(path, root));


            Duration duration = Duration.millis(1000);

            scene.setOnKeyPressed(event -> {
                System.gc();

                Text textNode = new Text(event.getText());
                textNode.setFont(Font.font(50));
                textNode.setFill(Color.ORANGE);
                root.getChildren().add(textNode);


                PathTransition pathTransition = new PathTransition();
                pathTransition.setDuration(duration);
                pathTransition.setPath(path);
                pathTransition.setCycleCount(1);

                pathTransition.setNode(textNode);
                pathTransition.setOnFinished(event1 -> {
                    root.getChildren().remove(textNode);
                    pathTransition.setNode(null);
                    pathTransition.setPath(null);
                    textNode.setFont(null);
                    textNode.setFill(null);
                });
                pathTransition.play();


            });
            primaryStage.show();
        }

        private void SetPathElements(Path path, Pane root) {
            path.getElements().clear();
            double w = root.getWidth();
            double h = root.getHeight();
            path.getElements().add(new MoveTo(w / 2, h));
            path.getElements().add(new LineTo(w / 2, -40));
        }
    }



EDIT #1

OS: Arch Linux 64-bit Platform: Intel i7-3rd generation, 8 GB ram IDE : Intellij JDK : 1.8.0_102

Proof of leak : After typing around 100 chars it jumped from 50 MB to 1.3 GB Memory leakage proof


EDIT #2

I have checked Heap size using jvisualvm and it indicates that the Heap expands greatly but the used portion don't exceed ~50 MB enter image description here

Shady Atef
  • 2,121
  • 1
  • 22
  • 40
  • 1
    I am able to run the you application with just 50MB , how you are saying it is consuming lot of memory? – ravthiru Oct 24 '16 at 23:21
  • Just keep writing a few letters and the memory will increase. – Shady Atef Oct 24 '16 at 23:23
  • @ShadyAtef I also ran this with the max heap set to 50m. If there were a memory leak it would give an out of memory error pretty quickly. I kept typing for a few minutes and it ran fine. What is your evidence there is a memory leak here? – James_D Oct 25 '16 at 00:02
  • 1
    There are many Q&A's on how to find a memory leak; e.g. search for "[java] find memory leak". (Native memory leaks are a bit more tricky ...) But first you need clear evidence that there >>is<< a leak ... otherwise you will be wasting your time looking for something that doesn't exist. – Stephen C Oct 25 '16 at 00:33
  • How much memory does it use? What OS and hardware do you use? – Itai Oct 25 '16 at 05:22
  • Check EDIT #1, I have provided a screenshot – Shady Atef Oct 25 '16 at 10:54
  • 2
    "Calling gc each time a new letter is printed": It is usually a bad idea to mess around with the garbage collector. Let it do it's work without interfering, it is optimized for that. – Henry Oct 25 '16 at 11:06
  • @Henry, Following your advice, the heap size is almost stable at 100 MB, but the system monitor still reports memory increase while typing. Also jvisualvm sampler reports the used memory is about 20 MB, so there is huge difference between what system monitor reports and what jvisualvm reports – Shady Atef Oct 25 '16 at 11:17
  • 1
    @ShadyAtef - There is a memory leak in JavaFX with Mesa >=11.0 (meaning any up to date Linux distribution). JavaFX developers say it's a bug in Mesa, but I couldn't find a bug report in Mesa (nor could I file one, as I don't know how to reproduce it outside of JavaFX). The only solutions as of now are - 1. Use an older Linux (the key is having Mesa 10 or lower); 2. Use an NVidia GPU - they have their own OpenGL implementation and don't rely on Mesa. 3. Use Windows. – Itai Oct 25 '16 at 11:48
  • @sillyfly, yes I have run the code with bumblebee optirun and it worked with max memory ~140 MB and no leaks Thank you. – Shady Atef Oct 25 '16 at 11:51
  • @sillyfly, write your comment as an answer, you deserve the points – Shady Atef Oct 25 '16 at 12:00

2 Answers2

5

There is a memory leak in JavaFX with Mesa >=11.0 (meaning any up to date Linux distribution). JavaFX developers say it's a bug in Mesa, but I couldn't find a bug report in Mesa (nor could I file one, as I don't know how to reproduce it outside of JavaFX).
The only solutions as of now are -
1. Use an older Linux (the key is having Mesa 10 or lower)
2. Use an NVidia GPU - they have their own OpenGL implementation and don't rely on Mesa.
3. Use Windows.

Update (November 2016)
This issue seems to have been resolved in newer versions of Mesa and/or X.org. Updating to Mesa 13.0 and X.org >=1.18.4 should solve this issue.

Related links:

Community
  • 1
  • 1
Itai
  • 6,641
  • 6
  • 27
  • 51
1

The upgrade up to Mesa 13.0.4 does not fix the issue, but there is a workaround.

If the program is run with -Dprism.order=j2d or -Dprism.order=sw VM argument, JavaFX rendering engine does not use OpenGL, and the leak does not happen. Of course, the application performance is significantly degraded in this case.

elmot
  • 71
  • 1
  • 4
  • Did you also upgrade X.org? Only updating Mesa is not enough, and has not solved the problem for me either, but with updated X.org *and* mesa the problem was solved. – Itai Mar 28 '17 at 08:12
  • I have upgraded the whole system – elmot Apr 24 '17 at 12:57
  • If your system (presumably Linux distribution?) didn't package the new versions, upgrading the whole system wouldn't do the trick. Verify your exact versions. – Itai Apr 24 '17 at 13:19