Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8208088

Memory Leak in ControlAcceleratorSupport





        When you repeatedly add a MenuItem in a Menu, a memory leak happens that can lead to severe performance issues.

         Step to reproduce:
        Run this sample :
        "import javafx.application.Application;
        import javafx.event.ActionEvent;
        import javafx.event.EventHandler;
        import javafx.scene.Scene;
        import javafx.scene.control.*;
        import javafx.scene.layout.BorderPane;
        import javafx.stage.Stage;

        public class HelloFX extends Application {

            public void start(Stage stage) {
                BorderPane pane = new BorderPane();
                MenuBar menuBar = new MenuBar();

                Menu menu = new Menu("TEST");
                MenuItem item = new MenuItem("toto");


                Button button = new Button("LEAK TEST");
                button.setOnAction(new EventHandler<ActionEvent>() {
                    public void handle(ActionEvent actionEvent) {
                        for(int i =0;i<10;++i){
                stage.setTitle("Hello World");
                stage.setScene(new Scene(pane, 300, 275));

            public static void main(String[] args) {

        - Run the Sample and take a profiler
        - Click on the button "LEAK TEST"
        - Take a heap dump and count the number of "ControlAcceleratorSupport$$Lambda"
        - Click again several times on the button
        - Take a new heap dump and you will see that you have a bunch more ControlAcceleratorSupport$$Lambda


        Each time we add a MenuItem inside the Menu, this line inside the Items ListChangeListener is called

         ControlAcceleratorSupport.doAcceleratorInstall(c.getAddedSubList(), scene);

        And inside this method, we do :
         // We also listen to the accelerator property for changes, such
                        // that we can update the scene when a menu item accelerator changes.
                        menuitem.acceleratorProperty().addListener((observable, oldValue, newValue) -> {
                            final Map<KeyCombination, Runnable> accelerators = scene.getAccelerators();

                            // remove the old KeyCombination from the accelerators map
                            Runnable _acceleratorRunnable = accelerators.remove(oldValue);

                            // and put in the new accelerator KeyCombination, if it is not null
                            if (newValue != null) {
                                accelerators.put(newValue, _acceleratorRunnable);

        Therefore we are adding a Listener to the acceleratorProperty() of this menuItem and we are never removing it. (Check removeAcceleratorsFromScene(c.getRemoved(), scene); that is called when the clear() is called on the Menu).

        Thus we are pilling up a bunch of Listeners on the MenuItem.

        This issue is present since JDK 8 and reproduced in JDK 11 build 23


          Issue Links



                arapte Ambarish Rapte
                shadzic Samir Hadzic
                0 Vote for this issue
                6 Start watching this issue