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

JFrame.setJMenuBar() results in leak with KeyboardManager

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 1.3.0
    • 1.2.0
    • client-libs
    • beta
    • generic
    • generic



        Name: dbT83986 Date: 04/07/99


        (Key words: JFrame, JMenuBar, memory leak, KeybordManager)

        Short: When a JMenuBar is set on a JFrame this will result in a reference to the JFrame in javax.swing.KeyboardManager. This reference will never
        be released...hence the JFrame will not get gc'ed.

        This bug has earlier been mentioned in bug report about InternalFrames (bugid 4177795). In that report it is also mentioned that there is a
        workaround for the JInternalFrame.

        This short code can be used to reproduce the problem

        //***********************************************************//
        import java.util.*;
        import javax.swing.*;
        import java.awt.event.*;

        public class Test {
        //--------------------------------------------//
        public static class TestFrame extends JFrame {
        public Integer myInteger;
        //----
        public TestFrame(int i) {
        myInteger = new Integer(i);
        }
        protected void finalize() throws Throwable {
        System.out.println("in finalizer " + myInteger);
        super.finalize();
        }
        public void dispose() {
        System.out.println("in dispose");
        //-----is this also a bug?????
        removeAll();//for JRootPane.parent????
        //-----
        super.dispose();
        }
        }
        //--------------------------------------//
        public static void main(String args[]) {
        Object synch = new Object();
        JFrame f = null;
        //--------------//create a few frames
        for (int i = 0; i < 15; i++) {
        f = new TestFrame(i);
        //--------
        f.setJMenuBar(new JMenuBar());//<----
        //-------
        f.pack();
        f.setVisible(true);
        synchronized (synch) {//wait before closing
        try {synch.wait(1000);}
        catch (Exception exc) {}
        }
        //----
        f.dispose();
        f = null;
        }//end of for
        //----------------------------//
        for (int i = 0; i < 100; i++)
        System.out.println("do some looping");
        System.runFinalization();
        System.gc();
        //----------------------------//
        //EXIT
        try {synchronized (synch) {synch.wait(3000);
        System.exit(0);}
        }catch (Exception exc) {}}}
        //********************************************************************//

        This is what will happen
        1)JFrame.setJMenuBar()----JRootPane.setJMenuBar()/setMenuBar()------JLayeredPane.add()
        2) JFrame.addNotify()-----JMenuBar.addNotify()--------KeyboardManager.registerMenuBar()
        3)JFrame.removeNotify()-----JMenuBar.removeNotify()------KeyboardManager.unregisterMenuBar()


        -----------------------------------------------------------
        Here is the code in KeyboardManager:
        //--------------------------------//
        public void registerMenuBar(JMenuBar mb) {
        Container top = getTopAncestor(mb);
        Hashtable keyMap = (Hashtable) containerMap.get(top);
        if (keyMap == null) { // lazy evaluate one
        keyMap = registerNewTopContainer(top);
        }
        Vector menuBars = (Vector) keyMap.get(JMenuBar.class); // use the menubar class as the key
        if (menuBars == null) { // if we don't have a list of menubars, then make one.
        menuBars = new Vector();
        keyMap.put(JMenuBar.class, menuBars);
        }
        menuBars.addElement(mb);
        //System.out.println("registered a menubar");
        }
        //--------------------------//
        public void unregisterMenuBar(JMenuBar mb) {
         Hashtable keyMap = null;
        Enumeration iter = containerMap.elements();
        while(iter.hasMoreElements()) {
        keyMap = (Hashtable)iter.nextElement();
        Vector v = (Vector)keyMap.get(JMenuBar.class);
        if (v != null) {
        v.removeElement(mb);
        }
         }
        }
        //-------------------------------//

        The method unregisterMenuBar(JMenuBar mb) will unregister the key actions but will leave the reference to the TopAncestor. Compare with the unregisterKeyStroke(KeyStroke ks, JComponent c) method to get the proper way to unregister.

        Since KeyBoardManager class has the default modifier there seems to be no way to work around it.

        If I am correct in my observations I would think that this bug should get very high priority. Moreover I have read about several leaks about JFrames in general so fixing this will probably not be enough.
        If I am misstaken i beg your pardon.

        //----------
        my version
        C:\vits>java -version
        java version "1.2"
        Classic VM (build JDK-1.2-V, native threads)
        C:\vits>java -fullversion
        java full version "JDK-1.2-V"
        (Review ID: 56662)
        ======================================================================

              gsaab Georges Saab
              dblairsunw Dave Blair (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: