-
Bug
-
Resolution: Fixed
-
P3
-
5.0
-
b136
-
x86
-
windows_xp
-
Verified
FULL PRODUCT VERSION :
reproduced on 1.4 & 1.5 see below;
java version "1.5.0_07"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-b03
Java HotSpot(TM) Client VM (build 1.5.0_07-b03, mixed mode, sharing)
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_11-b06)
Java HotSpot(TM) Client VM (build 1.4.2_11-b06, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
This occurs on any OS
A DESCRIPTION OF THE PROBLEM :
Dialogs that are created via createDialog in JOptionPane are never GC'd. The reason for this is because the PropertyChangeListener keeps hold of a reference to the JDialog this method creates.
The following code references a final variable declared in the method instead of correctly using the event.getSource() as code further up in this method does. This prevents the dialog from being GC'd
i.e.
addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
// Let the defaultCloseOperation handle the closing
// if the user closed the window without selecting a button
// (newValue = null in that case). Otherwise, close the dialog.
if(dialog.isVisible() && event.getSource() == JOptionPane.this &&
(event.getPropertyName().equals(VALUE_PROPERTY)) &&
event.getNewValue() != null &&
event.getNewValue() != JOptionPane.UNINITIALIZED_VALUE) {
dialog.setVisible(false);
}
}
});
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a dialog via JOptionPane, dispose the dialog check your profiler it is still allocated and may cause you to loose a window handle.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Dialog to be disposed
ACTUAL -
Dialog is still referenced to the JOptionPane class
ERROR MESSAGES/STACK TRACES THAT OCCUR :
N/A - no error
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
public class DialogTest {
public static void main(String args[]) {
JOptionPane pane = new JOptionPane(null, JOptionPane.UNDEFINED_CONDITION);
ArrayList references = new ArrayList();
for (int i=0; i < 10; i++) {
JDialog dialog = pane.createDialog(null, "Test " + i);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
{
// maintain a list of weak references so that
// we know how many dialog are still allocated post our test
WeakReference ref = new WeakReference(dialog);
references.add(ref);
}
dialog.dispose(); // force it to close
System.out.println("Disposing Dialog:" + dialog.hashCode());
}
System.out.println("Sleeping to allow for GC");
// try to free the dialogs, a sleep should only be neccesary but
// give the GC a chance.
for (int i=0; i < 100; i++)
{
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int originalDialogs = references.size();
int allocatedCount = 0;
for (Iterator iter = references.iterator(); iter.hasNext();) {
WeakReference ref = (WeakReference) iter.next();
if (ref.get() == null)
{
System.out.println("reference is empty bug not reproduced");
iter.remove(); // if the b
}
allocatedCount++;
System.out.println(ref.get().hashCode() + " is still allocated");
}
System.out.println(allocatedCount + " out of [" + originalDialogs + "] are allocated");
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Extend JOptionPane, override the createDialog method, this is not ideal as all classes that use JOptionPane now have to point to a new static class
reproduced on 1.4 & 1.5 see below;
java version "1.5.0_07"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-b03
Java HotSpot(TM) Client VM (build 1.5.0_07-b03, mixed mode, sharing)
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_11-b06)
Java HotSpot(TM) Client VM (build 1.4.2_11-b06, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
This occurs on any OS
A DESCRIPTION OF THE PROBLEM :
Dialogs that are created via createDialog in JOptionPane are never GC'd. The reason for this is because the PropertyChangeListener keeps hold of a reference to the JDialog this method creates.
The following code references a final variable declared in the method instead of correctly using the event.getSource() as code further up in this method does. This prevents the dialog from being GC'd
i.e.
addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
// Let the defaultCloseOperation handle the closing
// if the user closed the window without selecting a button
// (newValue = null in that case). Otherwise, close the dialog.
if(dialog.isVisible() && event.getSource() == JOptionPane.this &&
(event.getPropertyName().equals(VALUE_PROPERTY)) &&
event.getNewValue() != null &&
event.getNewValue() != JOptionPane.UNINITIALIZED_VALUE) {
dialog.setVisible(false);
}
}
});
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a dialog via JOptionPane, dispose the dialog check your profiler it is still allocated and may cause you to loose a window handle.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Dialog to be disposed
ACTUAL -
Dialog is still referenced to the JOptionPane class
ERROR MESSAGES/STACK TRACES THAT OCCUR :
N/A - no error
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
public class DialogTest {
public static void main(String args[]) {
JOptionPane pane = new JOptionPane(null, JOptionPane.UNDEFINED_CONDITION);
ArrayList references = new ArrayList();
for (int i=0; i < 10; i++) {
JDialog dialog = pane.createDialog(null, "Test " + i);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
{
// maintain a list of weak references so that
// we know how many dialog are still allocated post our test
WeakReference ref = new WeakReference(dialog);
references.add(ref);
}
dialog.dispose(); // force it to close
System.out.println("Disposing Dialog:" + dialog.hashCode());
}
System.out.println("Sleeping to allow for GC");
// try to free the dialogs, a sleep should only be neccesary but
// give the GC a chance.
for (int i=0; i < 100; i++)
{
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int originalDialogs = references.size();
int allocatedCount = 0;
for (Iterator iter = references.iterator(); iter.hasNext();) {
WeakReference ref = (WeakReference) iter.next();
if (ref.get() == null)
{
System.out.println("reference is empty bug not reproduced");
iter.remove(); // if the b
}
allocatedCount++;
System.out.println(ref.get().hashCode() + " is still allocated");
}
System.out.println(allocatedCount + " out of [" + originalDialogs + "] are allocated");
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Extend JOptionPane, override the createDialog method, this is not ideal as all classes that use JOptionPane now have to point to a new static class