如果我没记错的话,在Java中可以这样写
new JFrame();
不保存JFrame
任何变量中的引用。该程序将在屏幕上显示一个 GUI 窗口并使其保持打开状态,直到程序关闭。 (如果这个前提是错误的,请纠正我)。
理论上,我们可以认为自从 JFrame
现在用户代码无法访问该对象,GC 应在某个时刻释放该对象。因此,相关的操作系统资源(GUI 窗口等)也将被释放。
但是,如果我的理解是正确的 - 该程序是一个有效且可运行的 Java 程序(尽管是一个非常无用的程序),并且它在任何时候都不会崩溃或以奇怪的方式运行(如果这个前提是错误的,请再次纠正我) )。
看来GC不会收集JFrame
即使没有任何对它的引用,或者至少它不会导致关联的操作系统资源被释放。
我想了解:这怎么可能?
JFrame
的构造函数是否保存this
为了不被收集到任何地方?在 source code forJFrame
's superclass java.awt.Frame (方法noteFrame
)该帧似乎保存在弱引用队列中。但由于这些是弱引用,这似乎无法解释事情事实上GC确实最终释放了
JFrame
- 然而,JFrame
的终结器方法不释放关联的操作系统资源,因此 GUI 窗口保持打开状态?还有其他解释吗?
请注意,这是更多 theoretical question I posted on SE.SE 的后续问题。这个问题有所不同,因为它具体涉及 Java 实现细节。
最佳答案
仅通过 new JFrame()
创建且没有任何其他操作的 JFrame
将不会在屏幕上打开,也不会阻止垃圾回收。只有连接到显示设备的框架才会从 AWT 实现中引用,并且在显式断开连接之前无法进行垃圾收集。
可以使用以下代码验证:
public static void main(String[] args) {
check(new JFrame(), "just creating a JFrame", x -> {});
check(new JFrame(), "creating and connecting a JFrame", JFrame::pack);
check(Frame.getFrames()[0], "calling dispose()", Frame::dispose);
}
private static <T> void check(T obj, String description, Consumer<T> action) {
System.out.println(description);
action.accept(obj);
WeakReference<T> r = new WeakReference<>(obj);
obj = null;
System.gc();
if(r.get() == null) System.out.println("collected immediately");
else {
System.runFinalization();
System.gc();
if(r.get() == null) System.out.println("collected after finalization");
else System.out.println("still alive");
}
}
将打印
just creating a JFrame
collected immediately
creating and connecting a JFrame
still alive
calling dispose()
collected after finalization
在典型的实现中。
值得注意的是,从未连接到显示设备的框架会像普通对象一样立即被收集,而通过 dispose()
调用连接并随后断开连接的框架则需要清理操作,在第一次垃圾收集器运行后发生。
此外,该示例使用 pack()
而不是 setVisible(true)
来演示框架可以在不可见的情况下连接到显示设备。这使得 isDisplayable()
之间存在差异。它反射(reflect)组件是否连接到屏幕设备和 isVisible()
它告诉 visible 属性是否已设置为 true
。最后,组件仅报告 isShowing()
当它可见且可显示并且其所有父级都显示时,为 true
。
关于java - 为什么 JFrame 对象似乎保持 Activity 状态,即使没有对它的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60994544/