In OS X, Stages that are closed with the window decoration are never GC'd if the default close handling is used. I was only able to get simple stages to be collected if I handled the closing of the stage AND I used a runLater to perform the close in the WindowEvent handler.
Run the provided test class and show 2 windows with the left button and 2 windows with the right button. Close all the windows except the primary one and then click on the "Print References" button and watch the console.
The console will show that only 2 of the 4 created stages were GC'd.
***************************** Test Class ***********************************************
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Set;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class StageTest extends Application {
@Override public void start(final Stage primaryStage) throws Exception {
primaryStage.centerOnScreen();
primaryStage.setHeight(350);
primaryStage.setWidth(500);
final Set<WeakReference<Object>> refs = new HashSet<>();
Button showButton = new Button("New View (will collect)...");
showButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
Stage newStage = createNewStage(false);
newStage.show();
refs.add( new WeakReference<Object>(newStage) );
}
});
Button showButton2 = new Button("New View (won't collect)...");
showButton2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
Stage newStage = createNewStage(true);
newStage.show();
refs.add( new WeakReference<Object>(newStage) );
}
});
Button printButton = new Button("Print References");
printButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
Runtime.getRuntime().gc();
Set<WeakReference<Object>> collected = new HashSet<>();
for ( WeakReference<Object> ref: refs ) {
if ( ref.get() == null ) {
collected.add(ref);
}
}
refs.removeAll(collected);
System.out.println("*********************************************");
System.out.println(String.format("%d objects collected.",
collected.size()));
System.out.println(String.format("%d objects remain.",
refs.size()));
System.out.println("*********************************************");
}
});
VBox box = new VBox(20, new HBox(10, showButton, showButton2), printButton );
box.setMaxHeight(Region.USE_PREF_SIZE);
box.setMaxWidth(Region.USE_PREF_SIZE);
box.setAlignment(Pos.TOP_CENTER);
primaryStage.setScene(new Scene( new StackPane(box) ));
primaryStage.show();
}
private Stage createNewStage(boolean defaultClose) {
final Stage stage = new Stage();
stage.setScene(new Scene(new Pane(), 800, 600));
if ( !defaultClose ) {
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent event) {
event.consume();
// only collects if I "later" the hide
Platform.runLater(new Runnable() {
public void run() {
stage.hide();
}
});
}
});
}
return stage;
}
public static void main(String[] args) throws Exception {
launch(args);
}
}