Ronak Jain
Ronak Jain

Reputation: 2440

How to free the memory after closing JavaFX Stage?

I am creating a JavaFx application in which when I click on a button then it will open a table in new stage. But my problem is that when I close the stage of that table, memory is not getting free by the application. Is there anything wrong with javaFX? or I have to do something else?

I have tried to set everything null at the time of closing of that stage but still memory is not getting free.

Closing event on stage of table :

TableView tableView;

Stage myStage;

this.myStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent t) {
                TableController.this.myStage.close();
                tableView.getItems().clear();
                tableView.getColumns().clear();
                tableView = null;
                TableController.this.myStage = null;
                System.gc();
            }
        });

I have create a method called replaceScene to load scene using fxml file for stage. It will return it's controller and set scene into the Stage.

 public static Initializable replaceScene(String fXml, Stage mystage) {
    InputStream in = null;
    try {
        FXMLLoader loader = new FXMLLoader();
        in = Utility.class.getResourceAsStream(fXml);
        loader.setLocation(Utility.class.getResource(fXml));
        loader.setBuilderFactory(new JavaFXBuilderFactory());
        AnchorPane page;
        try {
            page = (AnchorPane) loader.load(in);
        } finally {
            in.close();
        }
        Scene scene = new Scene(page);
        mystage.setScene(scene);
        return loader.getController();
    } catch (Exception ex) {
        return null;
    }
}

I am first getting StreamObject (java.io.InputStream) for fxml file and then pass this streamObject to FxmlLoader to load the page,

in = Utility.class.getResourceAsStream(fXml);

I am getting object of sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream in the in inputstream object

Upvotes: 10

Views: 7475

Answers (2)

scottb
scottb

Reputation: 10084

I was about to post a very similar question. I must confess that I'm not a software engineer by training and my app development style probably relies on some "non-nuanced" practices and styles. One thing that I love about Java is the built-in memory management. One thing I don't love about Java is the built in memory management.

In Visual Basic 6, for example, you can be assured that once an object's reference count reaches zero that it will be destroyed. Implementing modal dialog windows in Visual Basic 6 was pretty simple:

Set myForm = new frmGetClientData
Call myForm.Initialize()
myForm.show, vbModal
nResult = myForm.getResult()
myForm.Hide()
Set myForm = nothing

As soon as the reference to myForm was cleared, it would be destroyed. This was convenient since you were assured that a new form would be constructed and initialized every time.

In Java, it is very hard to work with modal dialog windows. The dialog controller object doesn't know anything about the parent controller object unless passed a reference. Similarly the parent controller object must get a reference to the dialog controller if it needs to call methods on it. The parent controller, as it is constructing a new stage must get a reference to its own stage in order to set the modality of the dialog stage to modal.

With all these references pointing back and forth, it seems to me that in Java, a modal dialog window will never be garbage collected (because the references pointing back to the parent window and controller should remain valid) ... and that each time you use FXMLLoader to build and display a dialog window, a new large object will end up in memory with a very long life span. Using modal dialog windows in Java makes you have memory leaks, it seems to me.

One solution is to go into Visual Basic mode and be assiduous about releasing references to and from dialog windows and controllers when no longer used. What a hassle. This still doesn't provide any guarantees about when the window will be destroyed.

Another solution is to create a dialog pool and build them with initialization methods that set them to a known initial state each time you need them, rather than building a new window every time you want to show the dialog window (like I would do with Visual Basic).

Does anyone have insights about this with JavaFX? I am in the process of writing a helper class to help me build and manage modal dialog windows, but it seems to me that this really shouldn't be necessary. I may be just making extra work for myself.

Upvotes: 2

Kai
Kai

Reputation: 39632

There is nothing special for memory management and JavaFX. GC will run if the defined memory limit is reached. It doesn't run after setting an object = null. Even calling System.gc() doesn't mean the GC will run. From the Javadoc:

Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse.

To determine if you have a memory leak somewhere you could use VisualVM for example to see if (and why) your application gets out of memory.

Upvotes: 8

Related Questions