JDK-8094829 : Memory leak in JavaFX ProgressIndicator
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: 8u40,8u60
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2015-04-29
  • Updated: 2015-07-15
  • Resolved: 2015-05-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8u60Fixed
Related Reports
Relates :  
Description
Issue Description
=============
Whenever you create an indeterminate ProgressIndicator, it will stay in memory forever and with it everything that has a a reference to it.

This issue is quite critical since all our dialogs have kind of a "busy-glass-pane" showing an indeterminate progress indicator asa visual cue that "soemthing" is in progress and disabling mouse/key-inputs, etc. However, there's a workaround for it...

Workaround
=========
Apparently the ProgressIndicator is kept due to an infinite cycle-loop animation. So actually it will be OK memorywise to set progress to 1 (i.e. 100%) before getting rid of it.

Example
=======
Fire up and see that once you open a dialog a progress-indicator will be created and after you close the dialog it will never be GC'd.


package sandbox;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class ProgressIndicatorMemoryLeak extends Application {
	public static void main(String[] args) {
		launch(args);
	}

	@Override
	public void start(Stage primaryStage) throws Exception {

		Button openDialog = new Button("Open Dialog");
		openDialog.setOnAction(ae -> {

			ButtonType loginButtonType = new ButtonType("Login", ButtonData.OK_DONE);
			Dialog<String> dialog = new Dialog<>();
			dialog.getDialogPane().getButtonTypes().add(loginButtonType);

			ProgressIndicator indicator = new ProgressIndicator();
			BorderPane content = new BorderPane(indicator);
			content.setPadding(new Insets(20));
			dialog.getDialogPane().setContent(content);

			dialog.show();
		});

		BorderPane bp = new BorderPane();
		bp.setCenter(openDialog);

		Scene scene = new Scene(bp, 300, 300);
		primaryStage.setTitle("Memory Leak");
		primaryStage.setScene(scene);
		primaryStage.show();
	}
}
Comments
Changeset (8u60): http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/5c14e32365aa Changeset (9): http://hg.openjdk.java.net/openjfx/9-dev/rt/rev/3750d4a02e27
04-05-2015

This issue relates to RT-38894 in a sense. The problem that ProgressIndicator has is that it has no definitive way to know that it should stop the animation (treeVisible would seem like the best fit, but that seems....broken, as per my comment in RT-38894). Because of this, we sometimes find situations, such as in this bug report, where the ProgressIndicator timeline just happily keeps running as it doesn't know any better. In a sense, it is wrong to blame ProgressIndicator for this leak. In this instance, the dialog is being shown, the progress indicator timeline starts, and then the dialog is closed. One would assume that the progress indicator receives notification that the dialog is hidden and stops, but this isn't so, as by all properties that the progress indicator observes (notably: visible, parent, and scene), nothing has changed (that is, the progress indicator is still visible (it's just that the entire dialog is hidden), it still has the same parent (the dialog pane), and the scene is still the same). That means, for all intents and purposes, it would be wrong for the progress indicator to stop playing at this point! Again, for me, this is where having a correctly working treeVisible property would be immensely useful. So, to resolve this, I've worked from the opposite direction. Inside the dialog implementation, when the dialog is closed, I set the scene root to a dummy (but non-null, as per the scene root requirements) node. Then I set it back to the dialog pane when the dialog is about to be shown. This is more than a little unfortunate, but this at least allows for the ProgressIndicator to be informed that the scene has changed (to null, and then back to non-null), and as such properly handle the timeline (by stopping / starting it as expected). This will not fix the more general purpose issue of someone putting a ProgressIndicator inside a stage of their own, and then hiding the stage and expecting that the ProgressIndicator should properly handle this situation, but I can't reliably fix that without an API such as what I expect the treeVisible API should do. Again, RT-38894 delves into that a little deeper. I'll push this fix to 8u60 and 9 repos shortly.
04-05-2015

I can confirm the leak. Targeting to 8u60. We fixed a similar bug -- RT-38894 -- for 8u40. If I had to guess, this is another case that needs to be handled. A possible workaround might be to remove the ProgressIndicator from its parent panel when the dialog is closed (e.g., by adding a listener to your dialog).
29-04-2015