JDialog is never garbage collected
Why does the following code never garbage collect the开发者_如何转开发 JDialog instance ? The instance X has no reference and the dialog has been disposed.
public class Test {
public static void main(String[] args) throws Throwable {
test();
Runtime.getRuntime().gc();
}
public static void test() throws Throwable {
X x = new X();
x.setVisible(true);
x.dispose();
}
public static class X extends JDialog {
public X() {
super();
}
@Override
protected void finalize() throws Throwable {
System.out.println("destroyed !");
super.finalize();
}
}
}
Thank you
The question is (and some of the answers are) mixing two things, garbage collection and finalization. Runtime.getRuntime().gc() is just a hint that the collection should run and it’s very likely that the Dialog has been collected afterward (there’s still no guaranty). But this does not mean that the finalizer will run. The virtual machine will avoid running finalize methods as much as it can.
There is another issue with your test program. JDialog without a parent forces Swing to create an anonymous Frame as parent behind the scenes which will stay alive with unpredictable results (AWT runs within a different thread).
Try this test program:
import java.lang.ref.WeakReference;
import javax.swing.JDialog;
import javax.swing.JFrame;
public class Test {
public static void main(String[] args) throws Throwable {
WeakReference<JDialog> ref = test();
Runtime.getRuntime().gc();
System.out.println(ref.get()==null? "collected": "still flying around");
}
public static WeakReference<JDialog> test() throws Throwable {
JDialog d = new JDialog(new JFrame());
WeakReference<JDialog> ref = new WeakReference<JDialog>(d);
d.setVisible(true);
d.dispose();
d.getOwner().dispose();
return ref;
}
}
This works for me.
An alternative to Runtime.getRuntime().gc() is:
try {
byte[] b = new byte[Integer.MAX_VALUE];
} catch(OutOfMemoryError err) {}
as the vm guarantees performing gc before OOME (might not work with 64bit vms ;-) ).
The GC calls can't be expected at the specific time. It is called randomly or when there is full memory allocated by the JVM.
P.S. Your x.dispose();
don't call the GC. It may just mark that this object can be collected.
As was said before - you cannot expect GC at the specific time. But you can "force" it by filling up the memory.
try this code, it fills memory after disposing your class. It allocates a lot of Longs in loop but any bigger class would be better. (thought thi suffice on my defaults)
public class Test {
public static void main(String[] args) throws Throwable {
test();
Runtime.getRuntime().gc();
}
public static void test() throws Throwable {
X x = new X();
x.setVisible(true);
x.dispose();
//Fill memory:
for (int i = 0; i < Integer.MAX_VALUE; ++i) {
Long l = 10L;
}
}
public static class X extends JDialog {
public X() {
super();
}
@Override
protected void finalize() throws Throwable {
System.out.println("destroyed !");
super.finalize();
}
}
}
dialog the first one is never GC'ed, and there are some bugs with that, but unfor***, bugsParade is freeze now
dispose() has nothing to do with GC http://download.oracle.com/javase/6/docs/api/java/awt/Window.html#dispose%28%29
The JVM stops before the garbage collection needs to be run. Therefore the JDialog
is never garbage collected and thus never finalized.
精彩评论