JDK-8283551 : ControlAcceleratorSupport menu items listener causes memory leak
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: openjfx13
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2022-03-22
  • Updated: 2022-10-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.
Other
openjfx20Unresolved
Related Reports
Blocks :  
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Microsoft Windows [Version 10.0.17134.1040]
openjdk version "13" 2019-09-17
OpenJDK Runtime Environment AdoptOpenJDK (build 13+33)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 13+33, mixed mode, sharing)


A DESCRIPTION OF THE PROBLEM :
ControlAcceleratorSupport menu items listener is not cleared in removeAcceleratorsFromScene action, which causes memory leak while moving MenuBar with items to other scene. Removing is called in javafx.scene.control.skin.MenuButtonSkinBase#sceneChangeListener, but it does not handle the items' listener, so it just constantly adds new listeners on scene change, which grow up in memory.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Open provided TwoStagesMenuBarLeakSample.
2. Keep pressing F11.
3. Observe the ControlAcceleratorSupport count in memory analyzing tools - jvisualvm or Eclipse MAT.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
After 3. the ControlAcceleratorSupport count should be moreless the same as after 1.
ACTUAL -
lambda from ControlAcceleratorSupport  count keeps growing up in the memory causing memory leak

---------- BEGIN SOURCE ----------

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class TwoStagesMenuBarLeakSample
{

    public static void main( String[] args )
    {
        System.err.println( Runtime.version().toString() );
        Application.launch( TwoStagesMenuBarLeakSample.MainFx.class, args );
    }

    public static class MainFx extends Application
    {

        @Override
        public void start( final Stage primaryStage ) throws Exception
        {
            final BorderPane borderPane = new BorderPane( new VBox( new Label( "sample" ) ) );
            final Menu one = new Menu( "_One" );
            one.getItems().add( new MenuItem( "Sample 1" ) );
            one.getItems().add( new MenuItem( "Sample 2" ) );
            one.getItems().add( new MenuItem( "Sample 3" ) );
            one.getItems().add( new MenuItem( "Sample 4" ) );
            final var menuBar = new MenuBar( one );
            borderPane.setTop( menuBar );
            borderPane.setCenter( new Label( "Press F11 to switch MenuBar to other window." ) );
            Scene scene = new Scene( borderPane, 800, 600 );
            primaryStage.setScene( scene );
            primaryStage.show();
            final var stage2 = new Stage( StageStyle.DECORATED );
            final BorderPane stage2Container = new BorderPane();
            stage2Container.setCenter( new Label( "Press F11 to switch MenuBar to other window." ) );
            stage2.setScene( new Scene( stage2Container, 800, 600 ) );
            primaryStage.addEventHandler( KeyEvent.KEY_PRESSED, aKeyEvent -> {
                if( KeyCombination.keyCombination( "F11" ).match( aKeyEvent ) )
                {
                    stage2Container.setTop( menuBar );
                    stage2.requestFocus();
                }
            } );
            stage2.addEventHandler( KeyEvent.KEY_PRESSED, aKeyEvent -> {
                if( KeyCombination.keyCombination( "F11" ).match( aKeyEvent ) )
                {
                    borderPane.setTop( menuBar );
                    primaryStage.requestFocus();
                }
            } );
            stage2.show();
        }

    }

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Recreating menu bar on scene change.

FREQUENCY : always



Comments
Additional Information from submitter: ============================== The linked issue (JDK-8244075) is a separate bug, not related to current one, except it touches the same class. I have tested my issue on the latest JavaFX 17 and it is replicable there. Please run the test case and observe ControlAccelerationSupport's lambda's count growing in memory.
26-04-2022

Mail to submitter: ============= The issue has been resolved in Java FX 17 [1]. Please share your feedback checking in latest/early-access builds. [1] https://gluonhq.com/products/javafx/
23-03-2022