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

Memoryleaks with JMenu/Bar/Item with Windows-LookAndFeel (Motif is ok)

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      C:\>ver

      Microsoft Windows [Version 10.0.19042.985]

      C:\>java -version
      openjdk version "11.0.11" 2021-04-20 LTS
      OpenJDK Runtime Environment 18.9 (build 11.0.11+9-LTS)
      OpenJDK 64-Bit Server VM 18.9 (build 11.0.11+9-LTS, mixed mode)


      A DESCRIPTION OF THE PROBLEM :
      Changing the menubar in a frame does not free the unused menucomponents.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      After starting the example-application press the only button to toggle the menubar (severl times).
      Stop when only the File-menu is shown.
      Use VisualVM or other tool to see the current instances.
      There should be only 1 JMenuBar, 1 JMenu and 1 JMenuItem.
      This is true for the Motif-LookAndFeel (USE_WINDOWS_LAF = false)
      but not for the Windows-LookAndFeel (USE_WINDOWS_LAF = true)
      Use 'static boolean USE_WINDOWS_LAF = true;' to switch between test (restart application neccessary).



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      There should be only 1 JMenuBar, 1 JMenu and 1 JMenuItem (ok with Motif).

      ACTUAL -
      This is not true when the Windows-LookAndFeel is used.


      ---------- BEGIN SOURCE ----------
      public class MenuTest
        extends JFrame {

        // --- switch for L&F -> Windows-L&F leaks JMenuBar, JMenu, JMenuItem
        static boolean USE_WINDOWS_LAF = true;

        private static final String PREFIX = "PREFIX";

        private JPanel pnl;
        private boolean doFullMenu;
        // --- just to have it like in a real app
        private JMenuBar mMenuBar;
        private JMenu mFile;
        private JMenu mEdit;
        private JMenu mView;
        private JMenu mHelp;
        private JMenuItem miFile_New;
        private JMenuItem miFile_Open;
        private JMenuItem miFile_Print;
        private JMenuItem miFile_SwitchMenu;

        public MenuTest() {
          super("MenuTest " + UIManager.getLookAndFeel().getDescription() + " ("
            + UIManager.getLookAndFeel().getName() + ")");
          setDefaultCloseOperation(DISPOSE_ON_CLOSE);
          createContent();
        }

        private Action a(final String name, final ActionListener al) {
          return new AbstractAction(name) {
            @Override
            public void actionPerformed(final ActionEvent e) {
              al.actionPerformed(e);
            }
          };
        }

        private void createContent() {
          pnl = new JPanel(new GridLayout(1, 0));
          pnl.add(new JButton(a("switch menubar", ae -> installMB())));
          getContentPane().add(pnl);
          installMB();
          setMinimumSize(new Dimension(300, 100));
        }

        private void setMnem(final boolean forced, final boolean add2FLM,
          final AbstractButton ab, final String key) {
          final String mk = key + "_Mnem";
          final String mv = mk.substring(0, 1).toLowerCase();
          if (forced || !mv.equals(mk)) {
            final char c = mv.charAt(0);
            ab.setMnemonic(c);
          }
        }

        private JMenu crm(final String key) {
          final String miText = key;
          final JMenu m = new JMenu(miText);
          m.setName(PREFIX + "." + key);
          setMnem(true, true, m, key);
          return m;
        }

        private JMenuItem crmi(final String key, final String cmd, final KeyStroke ks,
          final ActionListener al) {
          final String miText = key;
          final JMenuItem mi = new JMenuItem(miText);
          mi.setName(PREFIX + "." + key);
          if (cmd != null)
            mi.setActionCommand(cmd);
          setMnem(false, false, mi, key);
          if (ks != null)
            mi.setAccelerator(ks);
          if (al != null)
            mi.addActionListener(al);
          return mi;
        }

        private final class ALSwitchMenu
          implements ActionListener {
          @Override
          public void actionPerformed(final ActionEvent e) {
            performSwitchMenu(e);
          }
        }

        private final class ALExit
          implements ActionListener {
          @Override
          public void actionPerformed(final ActionEvent e) {
            performExit(e);
          }
        }

        private void installMB() {
          // --- set null is neccessary !
          mMenuBar = null;
          mFile = null;
          mEdit = null;
          mView = null;
          mHelp = null;
          miFile_New = null;
          miFile_Open = null;
          miFile_Print = null;
          miFile_SwitchMenu = null;

          final JMenuBar mb = mMenuBar = new JMenuBar();
          mb.add(mFile = crm("File"));
          if (doFullMenu) {
            mb.add(mEdit = crm("Edit"));
            mb.add(mView = crm("View"));
            mb.add(mHelp = crm("Help"));
            mFile.add(miFile_New =
              crmi("New", "miFile_New", KeyStroke.getKeyStroke("alt N"), null));
            mFile.add(miFile_Open = crmi("Open", "miFile_Open", null, null));
            mFile.add(miFile_Print = crmi("Print", "miFile_Print", null, null));
            mFile.addSeparator();

            mFile.add(miFile_SwitchMenu =
              crmi("Switch menu", "miFile_SwitchMenu", null, new ALSwitchMenu()));
          }

          mFile.add(crmi("Exit", "miFile_Exit", null, new ALExit()));

          setJMenuBar(mb);
          revalidate();

          doFullMenu = !doFullMenu;
        }

        private void performSwitchMenu(final ActionEvent e) {
          installMB();
        }

        private void performExit(final ActionEvent e) {
          dispose();
        }

        public static void main(final String[] args) {
          if (USE_WINDOWS_LAF) {
            try {
              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (final Exception e) {
              e.printStackTrace();
            }
          }
          EventQueue.invokeLater(() -> {
            final MenuTest mt = new MenuTest();
            mt.pack();
            mt.setVisible(true);
          });
        }
      }

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

      FREQUENCY : always


        1. Capture_WINDOWS_LAF_false.PNG
          292 kB
          Praveen Narayanaswamy
        2. Capture_WINDOWS_LAF_true.PNG
          304 kB
          Praveen Narayanaswamy
        3. MenuTest.java
          4 kB
          Praveen Narayanaswamy

            tr Tejesh R
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: