JDK-4495338 : Dialogs are never garbage collected
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.4.0
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_98,windows_2000
  • CPU: x86
  • Submitted: 2001-08-23
  • Updated: 2017-03-29
  • Resolved: 2001-11-21
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.4.0 rc1Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description

Name: bsC130419			Date: 08/22/2001


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


I imagine this is already fixed in your internal betas, but just in case...

Dialogs in the 1.4 beta never become garbage collectable.  Conveniently, the
1.4 beta also won't let me use hprof, so I can't trace the pointer chain and
figure out why.

The following test case demonstrates the problem:

---

import javax.swing.*;

class TestDialog extends JDialog {
    String name;
    
    public TestDialog(String name) {
        this.name = name;
    }
    
    
    public void show() {
        super.show();
        dispose(); // so no user interaction is needed
    }
    
        
    public void finalize() {
        System.out.println(name + " being finalized");
    }
}


public class TestCase {
    public static void main(String[] arg) {
        TestDialog dialog1 = new TestDialog("Dialog1");
        TestDialog dialog2 = new TestDialog("Dialog2");
        TestDialog dialog3 = new TestDialog("Dialog3");
        
        // do nothing to Dialog1
        
        // pack Dialog2
        dialog2.pack();
        dialog2.dispose();
        
        // show Dialog3
        dialog3.show();
        
        // should be garbage collectable after this
        dialog1 = null;
        dialog2 = null;
        dialog3 = null;
        
        for (int i = 0; i < 20; i++)
            System.gc();
        
        System.exit(0);
    }
}

---

It works fine in JDK 1.3.1.  In JDK 1.4 beta, only Dialog1 is ever finalized.
This means that any dialog box which is ever shown (or even packed) can never
become garbage collectable, leading to a huge memory leak.
(Review ID: 130385) 
======================================================================

I tried the attached new sample program with 1.4.0fcs, this issue seems
to happen.

1. Reproducing

 1) Compile the new sample program(Fd2.java)
 2) Invoke "java Fd2"
    -> you will see a frame which has "Show Child Dialog" and "Cancel"
       buttons.
 3) Click the "Show Child Button"
    -> you will see a frame which has "File Dialogue" and "Cancel"
       buttons.
 4) Click the "File Dialogue"
    -> you will see a file dialogue for file selection.
 5) Click the "Cancel" button in the file dialogue which appeared 
    at the 4) opearation.
 6) Click the "Cancel" button on the frame which appeared at 3).
    -> you will be aware that you returns 2).
 7) Repeat from 2) to 6) for many times.
 8) Finally, you will see the following messages in the command prompt 
    window and opration freezed.

total=66650112byte,free=3621592byte
total=66650112byte,free=2014104byte
total=66650112byte,free=1974888byte
total=66650112byte,free=367736byte
total=66650112byte,free=328968byte
java.lang.OutOfMemoryError
total=66650112byte,free=291808byte
java.lang.OutOfMemoryError


2. Configration

  MPU: Pentium IV 1.4[GHz]
  Mem: 384[MB]
  OS : Windows2000 SP2 (Japanese)
  JDK: 1.4.0fcs

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

3. Note 
  - I attached an image file(leak.jpg) which shows how the memory becomes 
    short as a sample.
    This is the result with OptimizeIt4.11.
  - How many time should we repeat the 2)-6) loop in the above process ?
    It depends on each platform.
    With my PC, I repeated 50 times or so.

2002-03-26
================================================================================

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

SUGGESTED FIX ------- KeyboardFocusManager.java ------- *** /tmp/sccs.NHayV0 Thu Oct 4 14:23:30 2001 --- KeyboardFocusManager.java Thu Oct 4 14:23:23 2001 *************** *** 449,454 **** --- 449,487 ---- } /** + * Fix for 4495338. + * KFM's static references (notably focusedWindow and activeWindow) can + * keep Windows from being garbage collected if no other Window becomes + * focused/active after a Window is dispose()d. + * + * Called from Window.dispose() to clear any static references to the + * Window. + */ + static void clearStaticWindowRefs(Window ref) { + synchronized (KeyboardFocusManager.class) { + if (focusOwner == ref) { + focusOwner = null; + } + if (permanentFocusOwner == ref) { + permanentFocusOwner = null; + } + if (focusedWindow == ref) { + focusedWindow = null; + } + if (activeWindow == ref) { + activeWindow = null; + } + if (currentFocusCycleRoot == ref) { + currentFocusCycleRoot = null; + } + if (newFocusOwner == ref) { + newFocusOwner = null; + } + } + } + + + /** * Clears the global focus owner at both the Java and native levels. If * there exists a focus owner, that Component will receive a permanent * FOCUS_LOST event. After this operation completes, the native windowing ------- Window.java ------- *** /tmp/sccs.OHayV0 Thu Oct 4 14:23:30 2001 --- Window.java Wed Oct 3 20:34:39 2001 *************** *** 509,536 **** * @see #show */ public void dispose() { class DisposeAction implements Runnable { public void run() { synchronized(ownedWindowList) { for (int i = 0; i < ownedWindowList.size(); i++) { Window child = (Window) (((WeakReference) (ownedWindowList.elementAt(i))).get()); if (child != null) { child.dispose(); } } } setVisible(false); removeNotify(); synchronized (inputContextLock) { if (inputContext != null) { inputContext.dispose(); inputContext = null; } } } } DisposeAction action = new DisposeAction(); if (EventQueue.isDispatchThread()) { action.run(); --- 509,537 ---- * @see #show */ public void dispose() { class DisposeAction implements Runnable { public void run() { synchronized(ownedWindowList) { for (int i = 0; i < ownedWindowList.size(); i++) { Window child = (Window) (((WeakReference) (ownedWindowList.elementAt(i))).get()); if (child != null) { child.dispose(); } } } setVisible(false); removeNotify(); synchronized (inputContextLock) { if (inputContext != null) { inputContext.dispose(); inputContext = null; } } + KeyboardFocusManager.clearStaticWindowRefs(Window.this); } } DisposeAction action = new DisposeAction(); if (EventQueue.isDispatchThread()) { action.run();
11-06-2004

EVALUATION dialogs1 & 2 are finalized, but it appears 3 is not. This may be occuring because the exit happens so fast. ###@###.### 2001-08-22 This problem does not occur on 1.3.0 or 1.3.1 ###@###.### 2001-08-22 The problem seems to be if java.awt.Dialog.show() is invoked then the dialog will not be finalized. ###@###.### 2001-08-27 I have traced it with OptimizeIt. It appears that the LightweightDispatcher that java.awt.Container creates is not being properly disposed. ###@###.### 2001-09-17 Commit to Merlin ###@###.### 2001-09-25 According to OptimizeIt, KeyboardFocusManager is hanging onto the Dialog with some of its static members. A method in KeyboardFocusManager, called from Window.dispose(), which resets the static reference(s) to null if it refers to the Window, fixes the problem. See the suggested fix. ###@###.### 2001-10-03
03-10-2001

WORK AROUND Make another Window the Active/Focused Window. ###@###.### 2001-10-03
03-10-2001