-
Bug
-
Resolution: Fixed
-
P4
-
1.2.0, 1.2.2, 1.3.0
-
beta
-
generic, x86
-
generic, windows_nt
A user <###@###.###> submitted the following test application:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test implements ActionListener {
public static void main( String[] args ) {
new Test();
}
public Test() {
final JFrame f = new JFrame();
f.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
JButton b = new JButton( "test" );
b.addActionListener( this );
f.getContentPane().add( b );
f.pack();
f.setLocation( 500, 100 );
f.show();
}
public void actionPerformed( ActionEvent ae ) {
buildTestWindow();
}
public void buildTestWindow() {
final JFrame f = new JFrame();
JSplitPane sp = new JSplitPane();
f.getContentPane().add( sp );
sp.setLeftComponent( left() );
sp.setRightComponent( right() );
f.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
java.awt.event.WindowAdapter wa = new java.awt.event.WindowAdapter() {
public void windowClosing( java.awt.event.WindowEvent we ) {
f.dispose();
}
};
f.addWindowListener( wa );
f.pack();
f.setSize( 300, 300 );
f.show();
}
public JPanel left() {
JPanel lp = new JPanel();
lp.setLayout( new BorderLayout() );
Object[] o = { "aaaaaaaa", "bbbbbbbb", "cccccccc" };
JList l = new JList( o );
JScrollPane s = new JScrollPane( l );
lp.add( s, BorderLayout.CENTER );
return lp;
}
public JPanel right() {
JPanel rp = new JPanel();
rp.setLayout( new BorderLayout() );
JTabbedPane tp = new JTabbedPane();
tp.setTabPlacement( JTabbedPane.TOP );
addTab( tp, "one" );
addTab( tp, "two" );
addTab( tp, "three" );
rp.add( tp, BorderLayout.CENTER );
return rp;
}
public void addTab( JTabbedPane tp, String s ) {
JPanel p1 = new JPanel();
p1.setLayout( new BorderLayout() );
p1.add( new JButton( s ), BorderLayout.CENTER );
tp.add( s, p1 );
}
}
Run this program. Click the button several times to create several frames. Now close all the ones you created (except the original frame which the application displays. Run an explicit GC. Examining this with OptimizeIt shows there are 2 JFrames remaining in memory, not one. There should be only one.
Looking into this further, it becomes appearent that the second frame which remains is actually the first one you created by clicking on a button. It remains because it is stored in the "target" field of the Image object which Swing's repaint manager uses for a double-buffer. The only way to get rid of this leaked frame is to resize the tiny creator window to be bigger than any window so far created by the application. This will cause the repaint manager to create a new double-buffer slaved to the frame which is still in memory. The problem is now that if you close that frame it will leak.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test implements ActionListener {
public static void main( String[] args ) {
new Test();
}
public Test() {
final JFrame f = new JFrame();
f.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
JButton b = new JButton( "test" );
b.addActionListener( this );
f.getContentPane().add( b );
f.pack();
f.setLocation( 500, 100 );
f.show();
}
public void actionPerformed( ActionEvent ae ) {
buildTestWindow();
}
public void buildTestWindow() {
final JFrame f = new JFrame();
JSplitPane sp = new JSplitPane();
f.getContentPane().add( sp );
sp.setLeftComponent( left() );
sp.setRightComponent( right() );
f.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
java.awt.event.WindowAdapter wa = new java.awt.event.WindowAdapter() {
public void windowClosing( java.awt.event.WindowEvent we ) {
f.dispose();
}
};
f.addWindowListener( wa );
f.pack();
f.setSize( 300, 300 );
f.show();
}
public JPanel left() {
JPanel lp = new JPanel();
lp.setLayout( new BorderLayout() );
Object[] o = { "aaaaaaaa", "bbbbbbbb", "cccccccc" };
JList l = new JList( o );
JScrollPane s = new JScrollPane( l );
lp.add( s, BorderLayout.CENTER );
return lp;
}
public JPanel right() {
JPanel rp = new JPanel();
rp.setLayout( new BorderLayout() );
JTabbedPane tp = new JTabbedPane();
tp.setTabPlacement( JTabbedPane.TOP );
addTab( tp, "one" );
addTab( tp, "two" );
addTab( tp, "three" );
rp.add( tp, BorderLayout.CENTER );
return rp;
}
public void addTab( JTabbedPane tp, String s ) {
JPanel p1 = new JPanel();
p1.setLayout( new BorderLayout() );
p1.add( new JButton( s ), BorderLayout.CENTER );
tp.add( s, p1 );
}
}
Run this program. Click the button several times to create several frames. Now close all the ones you created (except the original frame which the application displays. Run an explicit GC. Examining this with OptimizeIt shows there are 2 JFrames remaining in memory, not one. There should be only one.
Looking into this further, it becomes appearent that the second frame which remains is actually the first one you created by clicking on a button. It remains because it is stored in the "target" field of the Image object which Swing's repaint manager uses for a double-buffer. The only way to get rid of this leaked frame is to resize the tiny creator window to be bigger than any window so far created by the application. This will cause the repaint manager to create a new double-buffer slaved to the frame which is still in memory. The problem is now that if you close that frame it will leak.
- duplicates
-
JDK-4256253 JFrame does not garbage collect
- Closed
- relates to
-
JDK-4277356 JFrame memeory leak
- Closed