import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.Stage;

public class TabsPaneControllerTest extends Application {

	private static final int LARGE_MEM_BYTES = 50_000_000;

	public static void main(String[] s) {
		launch();
	}

	@Override
	public void start(Stage primaryStage) {
		TabPane tabPane = new TabPane();

		Scene scene = new Scene(tabPane);
		primaryStage.setScene(scene);
		primaryStage.setMinHeight(300);
		primaryStage.setMinWidth(300);

		primaryStage.show();

		new Thread(() -> {
			runGc();
			printMem("without tab");

			addTab(tabPane);

			runGc();
			printMem("with tab, after gc");

			Platform.runLater(() -> {
				tabPane.getTabs().remove(0);
				System.out.println("Tab removed");
			});

// wait for tab removal
			while (!tabPane.getTabs().isEmpty()) {
				sleep(500);
			}
			runGc();
			printMem("removed tab, after gc");

			Platform.exit();
		}).start();

	}

	public void addTab(TabPane tabPane) {
		Platform.runLater(() -> {
			Tab tab = new Tab("HeavyTab");
			tab.setUserData(new byte[LARGE_MEM_BYTES]);
			tab.setContextMenu(new ContextMenu());

// reference to tab in MenuItem (onAction)
			MenuItem menuItemWithReferenceToTab = new MenuItem("RenameTabMenuItem");
			menuItemWithReferenceToTab.setOnAction(e -> tab.setText("tab renamed"));
			tab.getContextMenu().getItems().add(menuItemWithReferenceToTab);

			tabPane.getTabs().add(tab);
		});
	}

	public static void runGc() {
		System.gc();
		sleep(2000);
	}

	private static void sleep(int millis) {
		try {
			Thread.sleep(millis);
		} catch (Exception e) {
			e.printStackTrace(); // ignore
		}
	}

	public static void printMem(String message) {
		Runtime runtime = Runtime.getRuntime();
		long totalMemory = runtime.totalMemory() / 1024 / 1024;
		long freeMemory = runtime.freeMemory() / 1024 / 1024;
		System.out.println(message + "\t - used mem: " + (totalMemory - freeMemory) + " MB");
	}

}