0

I've been trying to figure out how to deal with memory leaks in a JavaFX application that I'm working on. I used the following code using FX8 to test memory behaviour:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Main extends Application {

    public int count = 0;

    @Override
    public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 500, 500, Color.BLACK);

        Rectangle r = new Rectangle(25,25,250,250);
        r.setFill(Color.BLUE);
        root.getChildren().add(r);

        scene.addEventHandler(KeyEvent.KEY_RELEASED, event -> {
            if (event.getCode() == KeyCode.SPACE) {
                event.consume();
                count++;
                Rectangle r2 = new Rectangle(25, 25, 250, 250); 
                r2.setFill(Color.BLUE);
                root.getChildren().clear();
                root.getChildren().add(r2);
            }
        });

        stage.setTitle("JavaFX Scene Graph Demo");
        stage.setScene(scene);
        stage.show();
    }

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

Whenever SPACE is pressed, root's children are cleared and a new rectangle is attached to root.

The problem with this code is that, as SPACE is pressed repeatedly, the amount of memory used by the Java application keeps increasing. Even when the application is left idle over some time afterwards, the amount of memory in use by the application does not decrease.

My impression is that the Rectangle objects should have been garbage collected, and yet the amount of memory does not decrease. Is this a problem with JavaFX, or is there something about Java garbage collection that I don't know about?


EDIT: Using System.gc() and YourKit

Following @AlmasB's answer, I added a System.gc() call to the callback, such that whenever SPACE is pressed, the GC is suggested to perform a garbage collection.

YourKit shows that garbage collections are indeed being carried out, and in fact, the amount of Heap & Non-Heap memory used, as shown by YourKit, stabilises after a while even as SPACE is repeatedly pressed.

TLDR: Even when GC is doing its job and YourKit reports stable memory, the memory consumption of the application continues to increase gradually as reported by Activity Monitor. Is this a problem with Activity Monitor then?

peco
  • 1,411
  • 3
  • 17
  • 38

1 Answers1

3

Garbage collection in Java is not meant to clean up after every single object goes out of scope without strong references. When your Rectangle object is no longer accessible, i.e. when you clear the root children, the object is simply marked for garbage collection but still remains in memory. You can read about it more here and more general info here. So technically speaking, depending on your JVM environment, GC might not even run during the lifetime of your application because there's enough memory for allocation of new objects.

If you still think that there's a memory leak, I suggest you use a proper profiling tool like VisualVM with VisualGC before worrying that JavaFX or GC might have a bug.

Community
  • 1
  • 1
AlmasB
  • 3,377
  • 2
  • 15
  • 17
  • So if GC _is_ run, then the memory in use by the application should decrease, and this should be reflected in Task Manager / Activity Monitor, yes? – peco Jul 02 '15 at 04:10
  • 2
    When GC runs it means JVM gets more free memory from its total memory, not OS. It will be reflected only if JVM itself gives the memory back to OS, which happens rarely. The allocation of native memory from OS to JVM is considered as an expensive operation. Hence generally JVM will keep the memory to itself until OS absolutely needs memory. This used to be the case anyway – AlmasB Jul 02 '15 at 06:38