JDK-8283449 : TabPane/Tab memory leak
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: jfx17
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2022-03-19
  • Updated: 2025-07-16
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.
Other
jfx26Unresolved
Related Reports
Relates :  
Relates :  
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Windows, Linux, JDK 17

A DESCRIPTION OF THE PROBLEM :
Memory is not released on tab removal, when the tab has a ContextMenu with MenuItem, that has reference to the tab.
Works well on javafx version 17-ea+12, but since 17-ea+13 problem exists. 
I think that the problem is in ControlAcceleratorSupport.java. Since this version a listener is always added to the "anchor", which is a TabPane in this case, so removing the tab does not release memory. 

 

REGRESSION : Last worked in version 16

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Result on 17-ea+12. Memory used after the tab is removed should be similar to memory used without the tab.

without tab	 - used mem: 20 MB
with tab, after gc	 - used mem: 76 MB
Tab removed
removed tab, after gc	 - used mem: 26 MB
ACTUAL -
Result on version 18 (same on 17-ea+13):

without tab	 - used mem: 16 MB
with tab, after gc	 - used mem: 76 MB
Tab removed
removed tab, after gc	 - used mem: 74 MB


---------- BEGIN SOURCE ----------
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");
	}

}
---------- END SOURCE ----------

FREQUENCY : always



Comments
This should be tested against JavaFX 18 as well, since that release has a fix for an additional memory leak in Control accelerators, JDK-8274022. UPDATE: I see from the above comment, that this bug is still present in JavaFX 18 and 19-ea. In that case, I think this is likely a new bug, and not a duplicate of an existing bug.
21-03-2022

I looked at the repo history, and confirmed that JDK-8244075 was first fixed in JavaFX 17+14, which makes it even more likely that it is the cause of this regression, given the observation in the description.
21-03-2022

JDK-8268374 is a behavioral bug regarding MenuItem accelerators in ContextMenu. This bug is a memory leak in TabPane, so does not seem to be (directly) related. Did you mean to close this as a duplicate of some other bug? UPDATE: Even if this is cause by some change in control accelerators, the Description indicates that it was introduced in JavaFX 17. JDK-8268374 was reported earlier (as affecting 16). This bug may or may not be a duplicate of some other bug. In looking at the changes that went into JavaFX 17, it looks possible that this bug was introduced by the fix for JDK-8244075, but that will need to be checked.
21-03-2022

The incident reported looks related to JDK-8268374, Marking as duplicate of JDK-8268374 Checked with attached testcase issue is reproducible, Test Result ======== openjfx17ea1: Pass openjfx17ea15: Fail openjfx18: Fail openjfx19ea3: Fail
21-03-2022