JDK-4191601 : Memory Leaks In JTable (really problem with JFrame.remove())
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.2.0,1.2.1
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,solaris_2.6,windows_nt
  • CPU: generic,x86,sparc
  • Submitted: 1998-11-19
  • Updated: 2013-11-01
  • Resolved: 1999-01-11
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
1.2.2 1.2.2Fixed
Related Reports
Duplicate :  
Relates :  
Description

Name: krT82822			Date: 11/19/98


There appears to be major memory leaks when using
swing components. The attached program
shows a dialog. After the dialog is closed and 
disposed, the dialog is never GC'd also leading
to an OutOfMemory error message.

Changing the app to use AWT components
fixes the leaks. This problem happens with 
JDK1.2rc1(win32) and JDK1.2rc2(win32) and 
JDK116 (Solaris) using swing103. I haven't tested
with other VM's.


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

public class PaulOne extends JFrame {
   JPanel topPanel = new JPanel();
   JButton pressButton = new JButton("Press Me");
   JButton exitButton = new JButton("Exit");
   JLabel label1 = new JLabel();

   public PaulOne() {
   	this.getContentPane().setLayout(new BorderLayout());
   	this.setSize(new Dimension(550, 65));
   	this.setTitle("Memory Leak Bug");
   	topPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
	pressButton.addActionListener(new java.awt.event.ActionListener() {
      	  public void actionPerformed(ActionEvent e) {
            pressButton_actionPerformed(e);
      	  }
   	});

        exitButton.addActionListener(new java.awt.event.ActionListener() {
      	  public void actionPerformed(ActionEvent e) {
            System.exit(0);
      	  }
   	});

   	this.getContentPane().add(topPanel, BorderLayout.NORTH);
   	topPanel.add(exitButton);
   	topPanel.add(pressButton);
   	topPanel.add(label1);
   	label1.setText("Free Memory: " + Runtime.getRuntime().freeMemory() );
        setVisible(true);
      }

      void pressButton_actionPerformed(ActionEvent e) {
        MyDialog centrePanel = new MyDialog();
	centrePanel.show();
	centrePanel.dispose();
	System.gc();
	label1.setText("Free Memory: " + Runtime.getRuntime().freeMemory() );
      }

      public static void main(String[] args) {
	 PaulOne f = new PaulOne();
      }
}

class MyDialog extends JDialog {
   TableModel dataModel = new AbstractTableModel() {
     public int getColumnCount() { return 10; }
     public int getRowCount() { return 30;}
     public Object getValueAt(int row, int col) { 
       return new Integer(row*col); 
     }
   };
   JButton closeButton = new JButton("Close Me");

   public MyDialog() {
     setSize(new Dimension(582, 431));
     getContentPane().setLayout(new BorderLayout());
     getContentPane().add( new JScrollPane( new JTable(dataModel) ),
        BorderLayout.CENTER);
     getContentPane().add( closeButton, BorderLayout.NORTH );
     getContentPane().add( new JLabel("Free Memory: " + 
        Runtime.getRuntime().freeMemory() ), BorderLayout.SOUTH );
     setTitle("Hello");
     setModal(true);
     closeButton.addActionListener(new java.awt.event.ActionListener() {
      	public void actionPerformed(ActionEvent e) {
           setVisible(false);
      	}
      });
   }
}
(Review ID: 43012)
======================================================================

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

EVALUATION The leaks are smaller than the test suggests because Runtime.getFreeMemory() isn't reliable (try clicking lots of times, and instead of steadily climbing, it jumps around). To get a more accurate picture of memory leakage, a memory profiler such as the heap profiler in 1.2 should be used, or a third-party package such as OptimizeIt. JDialog appears innocent of all leak charges. Nonetheless, the example shows significant leaks in JTable and JScrollPane. With JTable, the headers aren't being collected because of focus listeners added to support serialization. The BasicTableUI keyboard bindings aren't being removed, nor are several scrollpane ones. There are several other leaks. To analyze for leaks, run OptimizeIt with the PaulOne test (the Paul test is harder to use because it stops with a new table allocated, while PaulOne discards the table), click on the Inspector tab and enable the "Show sizes" feature -- this adds size and size diff. columns to the heap display. Next run the app, click on the GC button after it's finished initializing, and then click on the Mark Instance Count button. Open and close the dialog a few times (click on "Press Me" followed by "Close"), and then hit OptimizeIt's GC button again (moving the mouse around adds garbage since the last GC call made by the test). Click on the "Size diff." to sort for biggest leaks first. thomas.ball@Eng 1998-11-30 The first test program had the memory leak in itself: it added components with this.getContentPane().add(component), but tried to remove them with this.remove(component). Since the child component wasn't directly parented by the JFrame, the remove silently failed (the AWT should never have allowed silent failures like this, but now it's too late a practice to change). If you change the test program to call this.getContentPane().remove(component), the reported memory leak goes away. I'm still investigating the other test program. thomas.ball@Eng 1998-12-23 The major leaks appear to be in the table headers. Commenting out the JTable in the test case stops the significant leaking. thomas.ball@Eng 1998-12-23
23-12-1998