JDK-4193022 : Container.trackMouseEnterExit leaks memory
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 3.0,1.1.5,1.1.6,1.1.7,1.2.0,1.2.1
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS:
    generic,solaris_2.5.1,solaris_2.6,windows_nt generic,solaris_2.5.1,solaris_2.6,windows_nt
  • CPU: generic,x86,sparc
  • Submitted: 1998-11-25
  • Updated: 2013-11-01
  • Resolved: 1999-07-20
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 Other
1.1.8 1.1.8Fixed 1.2.2Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Description
Container.trackMouseEnterExit() calls startListeningForOtherDrags() when the mouse pointer enters the container.  It calls stopListeninForOtherDrags() when the mouse exits the container.

If the container is a window (in our case a JDialog), and the dispose() method is called while the mouse pointer is within the window (user clicks on the 'ok' button, for example), then the window is disposed, but no mouse exit event occurs.

This causes the window and everything it points to not to be collectable, as there is still the Container drag listener pointing at the window.


====================================================================================
Although this bug has been fixed for 1.2.2 we have a customer who is trying
to workaround the problem until then.  

We tested for the presence of bug 4193022 where JDialogs
do not get garbage collected. It is still present in jdk1.2.1-k

The work aroud reported in 4193022 does work for us in jdk1.2.1-k
but does not work in earlier jdk1.2 releases.

We used a slightly modified version of the sample program supplied
with bug 4193022.
We are currently working on propagating the  work around in 
our application and testing agianst 1.2.1-K.

The bug is reported closed and fixed agianst jdk1.8 and jdk1.2.2



--------------Cut Here--------

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

public class TAAPApplication
{
    JFrame aFrame = new JFrame("Tester");
    JDialog myDialog = null;

    public TAAPApplication()
    {
    aFrame.getRootPane().setMenuBar(createMenuBar());
    }

    protected JMenuBar createMenuBar()
    {
    JMenuBar myMenuBar = new JMenuBar();
    JMenu myMenu = new JMenu("Tester");

    myMenuBar.add(myMenu);
    JMenuItem myMenuItem = new JMenuItem("Press me");
    myMenu.add(myMenuItem);

    myMenuItem.addActionListener( new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    myDialog = new BigDialog();
    myDialog.pack();
    myDialog.show();
    }
    });

    return myMenuBar;
    }


    class BigDialog extends JDialog{
        int[] buffer = new int[1234567];
        JButton myButton = new JButton("Everytime you press me, I will leak");
        public BigDialog(){
          getContentPane().setLayout(new BorderLayout());
          getContentPane().add(myButton,BorderLayout.CENTER);
          myButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              myDialog.dispose();
            }
          });
        }
        }
/*** Uncomment to provide workaround****
        public final void dispose() {
          long now = System.currentTimeMillis();
          MouseEvent event = new MouseEvent(this,
          MouseEvent.MOUSE_EXITED, now, 0, 0, 0, 0, false);
          dispatchEvent(event);
          super.dispose();
        }
*********/
    }
    public JFrame getFrame() {
      return aFrame;
    }

    public static void main(String[] aArgs)
    {
      TAAPApplication myApp = new TAAPApplication();

      myApp.getFrame().addWindowListener( new WindowAdapter()
      {
        public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
      });

      myApp.getFrame().setSize(640,480);
      myApp.getFrame().setTitle("Tester");
      myApp.getFrame().setVisible(true);
    }
}
====================================================================================
Customer does not believe 4193022 or 4195507 have actually been fixed.

With the "fix" in place for 4193022, some but not all dialogs created, then closed, are released. Apparently, 
the "MyDialog" class is being referenced by a rootpane which is never released (ends up in a static list,
similar to bug 4195507 --- listed as closed in 1.2.1-c?). Puzzling to me is that some of the dialogs really 
are being garbage collected. By uncommenting the "this.setRootPane(null);" line in the dispose method, 
all "MyDialog"s (but one) are successfully garbage collected.


The following (MemBug.java) exhibits the problem:

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

class MyDialog extends JDialog
{
   public MyDialog()
   {
      final JButton myButton = new JButton("Everytime you press me, I will leak");
      myButton.addActionListener(new ActionListener() 
		 {
		    public void actionPerformed(ActionEvent e) 
		    {
		       MyDialog.this.setVisible( false );
		       MyDialog.this.dispose();
		       // myButton.removeActionListener( this );
		    } 
		 });
      
      getContentPane().setLayout(new BorderLayout());
      getContentPane().add(myButton, BorderLayout.NORTH);
      JPanel panel = new JPanel();
      panel.add(new JButton("One"));
      panel.add(new JButton("Two"));
      panel.add(new JButton("Three"));
      panel.add(new JButton("Four"));
      panel.add(new JTextField("Four"));
      panel.add(new JTextField("Four"));
      panel.add(new JTextField("Four"));
      panel.add(new JTextField("Four"));
      for (int i=0;i<25;i++)
	 panel.add(new JTextField("Four"));
      getContentPane().add(panel, BorderLayout.CENTER);
      
      setDefaultCloseOperation( DISPOSE_ON_CLOSE );
	
      pack();

   }
   /**********************************************
    * Dispose is overriden to fix a bug in
    * JDK 1.1.7. The Dialog adds itself as
    * an event listener to the event queue, but
    * only cleans up with a mouse exit. So force
    * an exit event during dispose. This is
    * tracked by JavaSoft as Bug # 4193022.
    * FIXX
    **********************************************/
   public final void dispose()
   {
      //   this.setRootPane(null);
      System.out.println("Dispose");
      long now = System.currentTimeMillis();
      MouseEvent event = new MouseEvent(this, MouseEvent.MOUSE_EXITED, now, 0, 0, 0, 0, false);
      dispatchEvent(event);
      super.dispose();
   }    
}

public class MemBug
{
   JFrame aFrame = new JFrame("Tester");
   JDialog myDialog = null;

   public MemBug()
   {
      aFrame.getContentPane().add(createButton());

   }

   protected JButton createButton()
   {
      JButton button = new JButton("Press Me");
      button.addActionListener( new ActionListener() {
	 public void actionPerformed(ActionEvent e) {
	    MyDialog myDialog = new MyDialog();
	    myDialog.show();
	    myDialog = null;
	 }
      });

      return button;
   }

   public JFrame getFrame() {
      return aFrame;
   }

   public static void main(String[] aArgs)
   {
      MemBug myApp = new MemBug();

      myApp.getFrame().addWindowListener( new WindowAdapter() {
	 public void windowClosing(WindowEvent e) {
	    System.exit(0);
	 }
      });

      myApp.getFrame().setSize(640,480);
      myApp.getFrame().setTitle("Tester");
      myApp.getFrame().setVisible(true);
   }
}

Compile with "javac MemBug"; execute; click the "Press Me" button to create a "MyDialog"; close the dialog by clicking on the "Every time you press...." button.



I added comments to 4193022 to reference 4195507 and provided the additional workaround.

Output of java -fullversion:

/D/Dr.J/Java/jdk_1.2.1/bin/java full version "JDK-1.2.1-K"

I'm listing that this problem causes my code to hang & crash, because within our application, significant quantities of data are present in the dialogs; over time, of course, the system drags to a halt as VM usage becomes dominant, resulting, finally, in a crash when resources are exhausted.

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.1.8 1.2.2 FIXED IN: 1.1.8 1.2.2 INTEGRATED IN: 1.1.8 1.2.2 VERIFIED IN: 1.1.8
14-06-2004

EVALUATION Evaluation in the description is correct. Adding Toolkit wide EventQueueListener keeps a reference to the LightweightDispatcher which in turns keeps a reference to the container, in this case a Dialog. robi.khan@eng 1999-02-02 ----------------------------------------------------------------------- This bug was verified as fixed via manual testing using jdk118m. al.smith@eng 1999-03-31
02-02-1999