为什么在超出作用域的情况下,需要使用dispose()来处理java.awt.Window?

9
我发现我们的应用程序中存在一个内存泄漏问题,其中一个私有静态字段java.awt.Window.allWindows跟踪每个实例化的Window。我们创建、使用并且忘记了对话框,期望它们会消失并被垃圾回收。但是这个私有字段会让它们一直处于范围内,直到调用dispose()方法。而且根据定义,当它们超出范围时,我们无法这样做。
我不明白为什么要设计成这样。这似乎与垃圾回收的精神相悖,因为我需要显式地告诉系统我已经完成了Window对象。显然,我已经完成了它,因为它已经超出了范围。
我理解dispose()方法的作用:清除系统对等体对象。我确实理解这是Java之外的部分,你需要某种方式来处理它,并且Swing不能只是失去这些对象的跟踪,否则就会出现内存泄漏。但是,将我的Window引用保留永远有何意义,当我再也不会使用它?
有人可以解释为什么这是必要的吗?

当调用 removeNotify 方法时,Window 将从 allWindows 中移除。 Window 包含本地资源,因此应该像处理数据库连接一样将其处理掉。 - Tom Hawtin - tackline
我曾经认为当我的数据库连接超出范围时,它们会自动关闭。我可能错了。:) 现在,除了短程序之外,所有这些都由服务器为我管理。 - skiphoppy
4个回答

14

很抱歉说这话,但这就是GUI工作的方式。

窗口是非阻塞的。这意味着一旦你在代码中创建了一个窗口,你的代码继续执行。

这意味着你的窗口可能立即超出范围,除非你明确将其引用存储在其他地方。此时,窗口仍然在屏幕上。

这也意味着你需要另一种方法来在使用完后摆脱它。这时可以使用Window dispose()方法,在窗口的监听器之一中调用它即可。


1
我明白了!人们经常创建一些窗口,但并没有保留其引用,但这些窗口仍然可见且在运行。我之前没考虑到这一点,因为在这种情况下,我们立即使用窗口然后将其隐藏起来,随后便忘记它(超出作用域)。现在我明白为什么这是窗口的默认设置了。我知道合理的使用场景总是存在的 :) - skiphoppy
哦,对了,我应该指出当 Window 变量超出作用域时它仍然在屏幕上显示。为了防止有人忽略这一点,我会在我的答案中加入编辑。 - Powerlord

2
这可能可以解释一下:AWT线程问题
简单来说,在JVM中发生的事情比可见组件要多得多,包括后台线程等资源。这些线程和其他资源会一直保持,直到JVM上的最后一个窗口被处理完毕,之后它们会被清理,JVM才能干净地退出。因此,您使用的每个窗口、框架和对话框实际上都在锁定JVM,以防止其退出,您必须通过调用dispose()手动管理它们。
我同意这有点麻烦。我自己也遇到过几次这种情况。

1

dispose() 方法销毁 WindowEvent 对象中持有的对象。它不会关闭应用程序/程序。


1
在Java中,当你有本地代码(这就是这些窗口组件的同行)时,你需要保留一个引用,以防止垃圾收集器在本地指针仍然存在时尝试回收对象,这会导致各种糟糕的事情发生(VM崩溃等)。
例如,请参见此处的讨论。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接