Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4759312
Votes 9
Synopsis JInternalFrame Not Being Finalized After Closing
Category java:classes_swing
Reported Against 1.4
Release Fixed
State 6-Fix Understood, bug
Priority: 3-Medium
Related Bugs 4748141
Submit Date 07-OCT-2002
Description


FULL PRODUCT VERSION :
java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)

and

java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

FULL OPERATING SYSTEM VERSION :
Windows XP, Service Pack 1

A DESCRIPTION OF THE PROBLEM :
Related to Bug ID 4748141.

If a single JInternalFrame is added to a JDesktopPane and
then closed, the instance is not available for garbage
collection UNTIL a new JInternalFrame is added to the
desktop.  It seems like even though the JInternalFrame has
been "disposed", a reference is still maintained to the
JInternalFrame as the selected window.  When the new
JInternalFrame is added, the reference is shifted allowing
the "disposed" JInternalFrame to be garbage collected.

In essence, this is a memory leak.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the code as shown in the Source Code section.  Click
the "Add Frame" button, close the initial frame, and click
the "Garbage Collect" button (sets the state to what is
described in bug ID 4748141).  Click the "Add Frame"
button, close the new frame, and click the "Garbage
Collect" button.  Note in the output window that the
println() statement in the finalize() method of the custom
JInternalFrame class does not trigger.  Now click the "Add
Frame" button followed by the "Garbage Collect" button.
You will see the println() statement in the finalize()
method of the original custom JInternalFrame() instance
trigger.
NOW, the original JInternalFrame is allowed to garbage
collect.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Should expect to see the finalize() method for the
JInternalFrame class to trigger after it has been disposed
of and the garbage collector fires.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class InternalFrameTest
{
    public static void main(String[] args)
    {
        JFrame frame = new JFrame("Internal Frame Test");
        frame.getContentPane().setLayout(new BorderLayout());
        final JDesktopPane desktopPane = new JDesktopPane();
        desktopPane.setDesktopManager(new DefaultDesktopManager());
        frame.getContentPane().add(desktopPane, BorderLayout.CENTER);
        
        InternalFrameListener iFrameListener = new InternalFrameAdapter() {
            public void internalFrameClosed(InternalFrameEvent evt)
            {
                System.out.println("Number of Frames Remaining=" +
desktopPane.getAllFrames().length);
            }
        };
        
//        for (int i = 0; i < 10; i++) {
//            JInternalFrame iFrame = new CustomInternalFrame("Frame " + i);
//            iFrame.setSize(200, 200);
//            iFrame.addInternalFrameListener(iFrameListener);
//            desktopPane.add(iFrame);
//            iFrame.setVisible(true);
//        }
       
        JButton button = new JButton("Add Frame");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt)
            {
                System.out.println("Adding new internal frame!");
                CustomInternalFrame iFrame = new CustomInternalFrame("Dummy
Frame");
                iFrame.setSize(200, 200);
                desktopPane.add(iFrame);
                iFrame.setVisible(true);
            }
        });
        frame.getContentPane().add(button, BorderLayout.NORTH);
        
        button = new JButton("Garbage Collect");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt)
            {
                System.out.println("Firing garbage collection!");
                System.gc();
            }
        });
        frame.getContentPane().add(button, BorderLayout.SOUTH);
        
        frame.setSize(800, 600);
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.setVisible(true);
        System.runFinalizersOnExit(true);
    }
    
    
    public static class CustomInternalFrame extends JInternalFrame
    {
        private static int iFrameIdCounter = 0;
        
        private int iFrameId;
        
        public CustomInternalFrame(String title)
        {
            super(title, true, true, true, true);
            iFrameId = iFrameIdCounter++;
        }
        
        protected void finalize()
        {
            System.out.println("Discarding frame " + iFrameId);
        }
    }
}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
None Identified
(Review ID: 165240) 
======================================================================
Posted Date : 2006-02-02 05:59:14.0
Work Around
N/A
Evaluation
Same evaluation as 4748141.
  xxxxx@xxxxx   2002-10-18
Contribution-forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?forumID=1463&messageID=11168


As   xxxxx@xxxxx   posted on that message, this bug (4759312)
should be closed as a DUP of 4836639.
Posted Date : 2006-02-02 05:59:15.0

Contribution-Forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?messageID=11168&forumID=1463
Posted Date : 2006-02-02 06:28:47.0

This bug may have been fixed by the fix for
    4683398: WindowsDesktopManager mantains a strong reference to currentFrame
Need to verify this in Dolphin.
Posted Date : 2006-06-13 01:33:53.0
Comments
  
  Include a link with my name & email   

Submitted On 14-OCT-2002
cforster
Yes, this has been around forever... If you look in Swing code 
you'll find that a ref to a single added JIF (last?) is always 
held (forget where... haven't looked in a while).

I seem to remember (using OptimizeIt) that this only results in 
a single persistent loss of <100K for the JDesktopPane 
instance (presuming you add an InternalFrameListener for 
closed(closing?) that clears any lingering refs, etc.).  You'll 
probably have at least one JIF on a showing JDesktop around 
anyway & it will need its space.  There are much bigger fish in 
the sea (mem leaks) waiting to be caught...


Submitted On 17-OCT-2002
jamock
The following workaround to the above code seems to 
correct the memory leak:

        final InternalFrameListener iFrameListener = new 
InternalFrameAdapter() {
            public void internalFrameClosed(InternalFrameEvent 
evt)
            {
                if (desktopPane.getAllFrames().length == 0)
                    
KeyboardFocusManager.getCurrentKeyboardFocusManager
().clearGlobalFocusOwner();
            }
        };


Submitted On 20-JAN-2003
takisd
i've been fiddling with this for months now. this is what i've 
noticed. yes there is a definite memory leak but for me occurs 
more often on the very first frame added to the desktop. 
THAT frame is never garbage collected (i'm using profilers).
i've also noticed that a particular internal frame i have 
with 'heavy' components and listeners is not garbage 
collected unless it is the second of these specific frames to 
be opened - ie. subsequent frames of this type are collected 
but never the first. i tried the work around listed and that 
didn't seem to work. what i've done now is simply add an 
empty internal frame to the desktop before any others and 
remove it immediately after the add() method. it is never 
garbage collected but minimises the memory leak to an empty 
frame as opposed to one with many components. not much of 
a work around but certainly mitigates the affects. i don't 
notice any other issues - another frame added to an empty 
desktop is ok as that first empty one is still hanging around. 
Takis


Submitted On 20-JAN-2003
takisd
i've been fiddling with this for months now. this is what i've 
noticed. yes there is a definite memory leak but for me occurs 
more often on the very first frame added to the desktop. 
THAT frame is never garbage collected (i'm using profilers). 
i've also noticed that a particular internal frame i have 
with 'heavy' components and listeners is not garbage 
collected unless it is the second of these specific frames to 
be opened - ie. subsequent frames of this type are collected 
but never the first. i tried the work around listed and that 
didn't seem to work. what i've done now is simply add an 
empty internal frame to the desktop before any others and 
remove it immediately after the add() method. it is never 
garbage collected but minimises the memory leak to an empty 
frame as opposed to one with many components. not much of 
a work around but certainly mitigates the affects. i don't 
notice any other issues - another frame added to an empty 
desktop is ok as that first empty one is still hanging around.


Submitted On 16-MAR-2004
sudhakar_it
hi


Submitted On 19-DEC-2005
Violetta
I'm still experiencing this problem on 1.5.


Submitted On 21-OCT-2006
There is an easy solution, at least in mustang.

The problem is in DefaultDesktopManager.closeFrame,
if the next frame is null the framesCache of the JDesktopPane
is not refreshed and remains a reference to the closed InternalFrame

The correct 

    public void closeFrame(JInternalFrame f) {
        JDesktopPane d = f.getDesktopPane();
        if (d == null) {
            return;
        }
        boolean findNext = f.isSelected();
        Container c = f.getParent();
-       JInternalFrame nextFrame = null;
-       if (findNext) {
-           nextFrame = d.getNextFrame(f);
            try { f.setSelected(false); } catch (PropertyVetoException e2) { }
-       }
        if(c != null) {
            c.remove(f); // Removes the focus.
            c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight());
        }
        removeIconFor(f);
        if(f.getNormalBounds() != null)
            f.setNormalBounds(null);
        if(wasIcon(f))
            setWasIcon(f, null);
-       if (nextFrame != null) {
-           try { nextFrame.setSelected(true); } 
-           catch (PropertyVetoException e2) { }
-       } else if (findNext && d.getComponentCount() == 0) {
-           // It was selected and was the last component on the desktop.
-           d.requestFocus();
-       }
+       if (findNext) {
+           d.selectFrame(true);
+       }
    }

With the call to d.selectFrame(true) at the end of the method, even if the 
next frame don't exists, selectFrame calls verifyFrame, the framesCache 
of the JDesktopPane is refreshed and the reference to the closed frame removed.


Submitted On 19-APR-2007
drokar
About the previous fix,

d.selectFrame(true) and d.getNextFrame(f) are not existing methods of JDesktopPane in JDK6 (Mustang)


Submitted On 19-APR-2007
drokar
I need a new pair of glass

forget my previous comment..... my mistake


Submitted On 28-NOV-2008
handsteiner
The priority is at least 2. the garbage collector has no chance to finalize the JInternalFrame. so if it is removed, the reference has to be nulled!!!
Same problems occures in the KeyboardFocusManager with static references and non static references in the current KeyboardFocusmanager who holds also unclearable references to components which are already removed.
if the handling with references is not well developed or designed, at least weakreferences should be used to prevent memory leaks!!!!!



PLEASE NOTE: JDK6 is formerly known as Project Mustang