JDK-4224393 : Memory leak while using swing's JDialog
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.2.0
  • Priority: P1
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_nt
  • CPU: x86
  • Submitted: 1999-03-26
  • Updated: 2022-10-21
  • Resolved: 1999-04-05
Related Reports
Duplicate :  
Relates :  
Description
me());
	m_gtwPortT.setText(Integer.toString(p.port()));
	m_gtwIPT.setText(p.address());
	m_userNameT.setText(p.userName());
	m_passWord1T.setText(p.userPassword());
	m_passWord2T.setText(p.userPassword());
      }

      public void actionPerformed(ActionEvent e)
      {
	if(e.getSource() ==m_commit)
	  {
	    GatewayObj g= new GatewayObj(m_gtwNameT.getText(), Integer.parseInt(m_gtwPortT.getText()), 	    	    	    	    	    	    	 m_gtwIPT.getText(),m_userNameT.getText(),
    	    	    	    	    	 m_passWord1T.getText());
	    
	    if(m_addflag == true)
	      {
		m_GtwPanel.addGateway(g);	
	      }
	    else 
	      {
		m_GtwPanel.modGateway(g);		
	      }
	    m_GtwPanel.enableButtons();
	    m_dialog.DestroyWindow();
	  }
	else if(e.getSource() ==m_clear)
	  {
	    if(m_addflag == true)
	      m_gtwNameT.setText("");
	    m_gtwIPT.setText("");
	    m_gtwPortT.setText("");
	    m_userNameT.setText("");
	    m_passWord1T.setText("");
	    m_passWord2T.setText("");
	  }
	else if(e.getSource() ==m_cancel)
	  { 
	    m_dialog.DestroyWindow();
	  }
	else
	  {;}
      } 
    
      private JLabel m_gtwNameL, m_gtwIPL, m_gtwPortL, m_userNameL, m_passWord1L,m_passWord2L;
      private JTextField m_gtwNameT, m_gtwIPT, m_gtwPortT, m_userNameT;
      private JPasswordField m_passWord1T,  m_passWord2T;
      private GridBagLayout m_gl;
      private GridBagConstraints m_gc;
      private JButton m_commit, m_clear, m_cancel;
      private JFrame m_frame;
      private AddModGTWDialog  m_dialog;
      private  boolean m_addflag;
    }
  }

  class GatewayObj 
  {
    int     _port;
    String  _gtwName;
    String  _gtwAddress;
    String  _userName ;
    String  _userPassword;
    
    public GatewayObj
    (
     String name,
     int port,
     String address,
     String userName,
     String userPassword
      )
    {
      _port = port;
      _gtwName = name;
      _gtwAddress = address;
      _userName = userName;
      _userPassword = userPassword;      
    }
    
    public int port(){return _port; }
    public String gatewayName(){ return _gtwName; }
    public String address(){ return _gtwAddress; }
    public String userPassword(){ return _userPassword; }
    public String userName(){ return _userName; }

    public void setgtwName(String name) {_gtwName = name;}
    public void setgtwport(int port) { _port = port;}
    public void setgtwAddress(String address){ _gtwAddress = address;}
    public void setuserName(String  userName) {_userName = userName;}
    public void setuserPassword(String userPassword) {_userPassword = userPassword;}

  }
}
synopsis : JDialog's finalize method is not getting called on NT-jdk1.2.
description : I wrote a small program to launch and dispose a derived
class of JDialog() on NT using JDK1.2.

But when I dispose the dialog, I don't see the finalize()
method being called in the derived class of JDialog.

The same thing works fine using JDK1.1.7B compiler.

Here is how I dispose the dialog:

testAppDialog.setVisible(false);
testAppDialog.dispose();
testAppDialog = null;   
System.gc();

I know System.gc() doesn't get called immediately, but
finalize() does not get called even after repeatedly 
creating and destroying the dialogs.

BTW, on NT, I can see that the memory of the java.exe
keeps growing up and eventualy running out of memory.



++++++++++++++++++++++++++++++++++++++++++++++++++++++


We are having memory leak problem whenever we create a swing JDialog and dispose it later. This problem
shows up when we use JDK1.2 on NT. 

For your convenience,  we have enclosed two examples as test cases. First test case follows this message 
and another one is enclosed with this e-mail as two text documents.

----------------------------------------------------------------------------
Instructions for 2 nd Test Case
----------------------------------------------
In order to use the attached test case, simply compile both the java files
and run the application 
using command:

	$ java Application1 
When you dispose the dialog, you will see that the finalize() method is not
being called in the dialog class.

----------------------------------------------------------------------------
1 st Test Case
--------------------------
Another example follows this e-mail with the required instructions:
Hello, Vasuraj,

I made a simple code to test the memory leaking problem in java 1.2.

Here is the the instructions to run it:
1>Type in "Java Mem" to run it.
2> click "Add" Button, you will see a dialog box pop up.
3> You can type in anything in those textfields.
4>click "Cancel" 

If you open Window NT Task manager, you can get the performance information. By doing step 2, Memory usage will increase. When finished step 4, memory usage will decrease a little ,but you can see not all the memory has been released. As time goes by, the memory usage will keep increasing.

When we run our real application, which is much much bigger than this simple  code, we noticed  the speed will be slower and slower and memory usage keeps increasing.

So we suspect there might be a memory leaking problem in java 1.2. Each time when we close the dialog, we did call Dispose() function which is suppose to release the resources for the Window, all of its contained 
children, and all of its owned Windows will be destroyed, and any memory they consume returned to the OS.

Thanks!

Yao
_____________________

import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.net.URL;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.table.TableModel;
import javax.swing.table.TableColumn;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.AbstractTableModel;

public class Mem extends JFrame 
{
  private GtwPanel m_GtwPanel;
  private  String m_password;

  public Mem()
  {
    super(" CNM Gateway Login Window ");
    initView();
  }
  
  public void initView()
  {
    m_GtwPanel =new GtwPanel(this);
   
    this.getContentPane().setLayout( new BorderLayout());    
    this.getContentPane().add("Center",m_GtwPanel);    
  }

  public GatewayObj getGatewayObj()
  {
    return m_GtwPanel.getGatewayObj();
  }

  public static void main(String[] args)
  {
    Mem memorytest = new Mem();
    memorytest.pack();
    memorytest.setSize(400, 250);
    memorytest.setVisible(true);    
  }
  class GtwPanel extends JPanel implements ActionListener
  {
    Mem _parenth; 
    public GtwPanel(Mem v)
    {
      super();

      _parenth = v;

      this.setLayout( new BorderLayout());    
      initView();
    }
  

    private void initView()
    {
      Vector columnName=new Vector();
      columnName.addElement("Gateway Name");
      columnName.addElement("IP Address");
      columnName.addElement(" Gateway Port");
      columnName.addElement("User Name");

      m_gtwModel=new GatewayTableModel(columnName);
      m_gtwTable = new JTable(m_gtwModel);    

      JScrollPane m_scrollPane = new JScrollPane(m_gtwTable);
      
      m_gtwTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);    
      m_gtwTable.setShowGrid( true);

      m_gtwTable.setCellSelectionEnabled( false);
      m_gtwTable.setColumnSelectionAllowed( false);
      m_gtwTable.setRowSelectionAllowed( true);

      installListListener();      

      m_del = new JButton("Delete");
      m_del.setEnabled( false);
      m_del.addActionListener( this);

      m_mod = new JButton("Modify");
      m_mod.setEnabled( false);
      m_mod.addActionListener( this);
  
      m_add= new JButton("Add");
      m_add.addActionListener( this);

      m_login =new JButton("Login");
      m_login.addActionListener(this);

      m_cancel =new JButton("Cancel");
      m_cancel.addActionListener(this);
     
      JPanel buttonPanel = new JPanel();
      buttonPanel.setLayout( new FlowLayout());   
      buttonPanel.add(m_mod);
      buttonPanel.add(m_add);
      buttonPanel.add(m_del);
      buttonPanel.add(m_login);
      buttonPanel.add(m_cancel);
      
      this.add("Center", m_scrollPane);
      this.add("South",  buttonPanel);
    }

    public void addGateway(GatewayObj g)
    {
      Vector v=m_gtwModel.getTableVector();
      v.addElement(g);
      m_gtwModel.updateTable(v); 
    }

     public void modGateway(GatewayObj g)
    {
      Vector v=m_gtwModel.getTableVector();
      v.removeElementAt(m_selection);
      v.insertElementAt(g, m_selection);
      m_gtwModel.updateTable(v); 
    }

    public GatewayObj getGatewayObj()
    {
       Vector v=m_gtwModel.getTableVector();
       return (GatewayObj)v.elementAt(m_selection);
    }
    
    private void installListListener()
    {
      ListSelectionModel rowSM = m_gtwTable.getSelectionModel();
      rowSM.addListSelectionListener
	(
	new ListSelectionListener() 
	{
	   public void valueChanged(ListSelectionEvent e) 
	     {
	       ListSelectionModel lsm = (ListSelectionModel)e.getSource();
	       if (lsm.isSelectionEmpty()) 
		{
		   m_del.setEnabled( false);
		   m_mod.setEnabled( false);
		} 
	       else 
		{
		   m_del.setEnabled( true);
		   m_mod.setEnabled( true);
		   m_selection = lsm.getMinSelectionIndex();
		}
	     }
	});
    }    
   
    public void actionPerformed(ActionEvent e)
    {
      if(e.getSource() == m_del)
	{
	  Vector v=m_gtwModel.getTableVector();
	  v.removeElementAt(m_selection);
	  m_gtwModel.updateTable(v);
	
	  if(v.size() ==0)
	    {
	      m_del.setEnabled(false);
	      m_mod.setEnabled(false);
	    }
	}
      else if(e.getSource() == m_mod)
	{
	  AddModGTWDialog a = new AddModGTWDialog(_parenth, "Modify Gateway", false);
	  a.show();
	}
      else if(e.getSource() == m_add)
	{
	  AddModGTWDialog a = new  AddModGTWDialog(_parenth, "Add Gateway", true);
	  a.show();
	}
      else if(e.getSource() == m_login)
	{
	  ;
	}
      else if(e.getSource() == m_cancel)
	{
	  setVisible(false);
	  dispose();
	  System.gc();
	  System.exit(0);
	}
	;
    }

  
   
    public void enableButtons()
    {
      m_del.setEnabled( true);
      m_mod.setEnabled( true);
    }
    
    public GatewayTableModel getTableModel()
    {
      return m_gtwModel;
    }

    private GatewayTableModel m_gtwModel;
    private JTable m_gtwTable;
    private JButton m_del, m_add, m_mod, m_login,m_cancel;
    private Vector m_gtwData;
    private int m_selection;
    private JFrame m_frame;
  }



  class GatewayTableModel extends AbstractTableModel
  { 
    private Vector columnName;
    private Vector tableVector=new Vector();

    public GatewayTableModel(Vector m_columnNames)
    {
     columnName=m_columnNames;
    }

    public final int getColumnCount() {return columnName.size();}
    public final int getRowCount() {return tableVector.size();}
    public final String getColumnName(int col) {return (String)(columnName.elementAt(col));}
    public final Vector getTableVector(){return tableVector;}

    public final void updateTable(Vector v)
    {
      tableVector=v;
      fireTableDataChanged(); 
    }
    
    public String getKey(int i) 
    {
      Vector data=getTableVector();
      return  ((GatewayObj)(data.elementAt(i))).gatewayName();
    }
    
    public Object getValueAt(int row,int col)
    {
      try
	{
	  Vector data=getTableVector();  
	  GatewayObj p = (GatewayObj)data.elementAt(row);
	  switch (col) 
	    {
	    case 0:
	      return p.gatewayName() ;
	    case 1:
	      return p.address();
	    case 2:
	      return Integer.toString(p.port());
	    case 3:
	      return p.userName();
	    case 100:
	      // Return the whole object
	      return p;
	      }
	}
      catch (Exception e)
	{
	  return "";
	}
      return "";
    }

    public boolean isCellEditable(int row, int col) 
    {
      return  false ;
    }
    
    public void setValueAt(Object value, int row, int col) 
    {               
      Vector data=getTableVector();
      GatewayObj p = (GatewayObj)data.elementAt(row);
      switch (col) 
	{
	case 0:	
	  p.setgtwName((String)value);
	  break; 
	case 1:
	  p.setgtwAddress((String)value);
	  break;
	case 2:
	  p.setgtwport(Integer.parseInt((String)value));
	  break;
	case 3:
	  p.setuserName((String)value);
	  break;
	}

      fireTableCellUpdated(row, col);
    }
  }

  class AddModGTWDialog extends JDialog
  {
    public AddModGTWDialog(JFrame frame, String title, boolean addFlag1)
    {
      super( frame, title, true);      
      addGtwPanel m_addGtwPanel=new addGtwPanel(frame,this, addFlag1); 
      this.getContentPane().setLayout(new BorderLayout());
      this.getContentPane().add(m_addGtwPanel);
      this.setSize(new Dimension(500,250));
    }

    public void DestroyWindow()
    {
      setVisible(false);
      dispose();
    }

    class addGtwPanel extends JPanel implements ActionListener 
    {
      public addGtwPanel(JFrame frame, AddModGTWDialog d, boolean addflag)
      {
	m_frame=frame;
	m_dialog=d;
	m_addflag=addflag;
	m_gl = new GridBagLayout();
	m_gc = new GridBagConstraints();
	
	this.setLayout(m_gl);
	
	initView(); 

      	if(m_addflag == false)
	  {
	    GatewayObj g=((Mem)m_frame).getGatewayObj();
	    
	    updateView(g);
	  }
      }
      
      public void initView()
      {      
	m_commit= new JButton(" OK ");
        m_commit.setEnabled( false);
	m_commit.addActionListener(this);
	
	m_clear = new JButton("Clear"); 
	m_clear.addActionListener(this);
	
	m_cancel =new JButton("Cancel");
	m_cancel.addActionListener(this);
	
	
	m_gtwNameL= new JLabel("Gateway Name :");
	m_gtwNameT = new JTextField(20);
	if(m_addflag == false)
	  m_gtwNameT.setEnabled(false);
	
	m_gtwIPL = new JLabel("Gateway IP Address:");
	m_gtwIPT = new JTextField(20);

	m_gtwPortL = new JLabel("Gateway Port:");
	m_gtwPortT = new JTextField(20);
	
	m_userNameL = new JLabel("User Name:");
	m_userNameT = new JTextField(20);
	
	m_passWord1L = new JLabel("User Password:");
	m_passWord1T = new  JPasswordField(20);
	//	m_passWord1T.setEchoChar('*');
	
	m_passWord2L = new JLabel("Retype User Password:");
	m_passWord2T = new JPasswordField(20);
	//m_passWord2T.setEchoChar('*');
	
	m_gc.gridx = 0;
	m_gc.gridy = 0;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_gtwNameL, m_gc);
	this.add(m_gtwNameL);
	
	m_gc.gridx = 2;
	m_gc.gridy = 0;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_gtwNameT, m_gc);
	this.add(m_gtwNameT);
      
	m_gc.gridx = 0;
	m_gc.gridy = 1;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_gtwIPL, m_gc);
	this.add(m_gtwIPL);
	
	m_gc.gridx = 2;
	m_gc.gridy = 1;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_gtwIPT, m_gc);
	this.add(m_gtwIPT); 
	
	m_gc.gridx = 0;
	m_gc.gridy = 2;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_gtwPortL, m_gc);
	this.add(m_gtwPortL);

	m_gc.gridx = 2;
	m_gc.gridy = 2;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_gtwPortT, m_gc);
	this.add(m_gtwPortT); 

	m_gc.gridx = 0;
	m_gc.gridy = 3;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_userNameL, m_gc);
	this.add(m_userNameL);

	m_gc.gridx = 2;
	m_gc.gridy = 3;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_userNameT, m_gc);
	this.add(m_userNameT);

	m_gc.gridx = 0;
	m_gc.gridy = 4;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_passWord1L, m_gc);
	this.add(m_passWord1L);

	m_gc.gridx = 2;
	m_gc.gridy = 4;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_passWord1T, m_gc);
	this.add(m_passWord1T);

	m_gc.gridx = 0;
	m_gc.gridy = 5;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_passWord2L, m_gc);
	this.add(m_passWord2L);

	m_gc.gridx = 2;
	m_gc.gridy = 5;
	m_gc.gridwidth = 2;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(m_passWord2T, m_gc);
	this.add(m_passWord2T);

	JPanel buttonPanel = new JPanel();
	buttonPanel.setLayout( new FlowLayout(FlowLayout.RIGHT));
	buttonPanel.add(m_clear);
	buttonPanel.add(m_commit);
	buttonPanel.add(m_cancel);
      
	m_gc.gridx = 0;
	m_gc.gridy = 6;
	m_gc.gridwidth = 4;
	m_gc.anchor = GridBagConstraints.NORTHWEST;
	m_gc.fill = GridBagConstraints.NONE;
	m_gc.insets = new Insets(2, 0, 0, 0);
	m_gl.setConstraints(buttonPanel, m_gc);
	this.add(buttonPanel);
      }

      private void updateView(GatewayObj p)
      {
	m_gtwNameT.setText(p.gatewayNa

Comments
WORK AROUND Here is the workaround for stopping the memory leak in JDialog: I added the following recursive method in the derived class of the JDialog. public void removeComponents(Container cont) { Component[] components = cont.getComponents(); for (int i = 0; i < components.length; i++) { Component comp = components[i]; if (comp != null) { if (comp instanceof Container) removeComponents((Container) comp); // Remove all the listeners if (comp instanceof FWFreeResources) ((FWFreeResources)comp).freeResources(); System.out.println("Removing component...\n" + comp.toString()); cont.remove(comp); comp = null; } } // Make sure this dialog also removes all its registered listeners if (this instanceof FWFreeResources) ((FWFreeResources)this).freeResources(); if (cont instanceof Window) ((Window) cont).dispose(); } ---------------------------------------------------------------------------- In the GUI class, I added the following interface to remove all the registered listeners. public interface FWFreeResources { public void freeResources(); } Example of the freeResources() implementation: public void freeResources() { System.out.println("INTERFACE Freeing resources in the view...\n"); helpBut.removeActionListener((TDialogSwitchController)controllerHandle); closeBut.removeActionListener((TDialogSwitchController)controllerHandle); contBut.removeActionListener((TDialogSwitchController)controllerHandle); }
11-06-2004

EVALUATION This bug indeed STILL exists in 1.2.1 and is NOT a duplicate of 4193022. amy.fowler@Eng 1999-03-30 This leak appears to be fixed in 1.2.2 (didn't realize 1.2.1 was 1.2.0 plus security fix ONLY), so is in fact a dup of 4193022. amy.fowler@Eng 1999-04-05
30-03-1999