在运行时删除顶级容器
不幸的是,它看起来最近关闭了 问题没有被很好地理解。这是典型的输出:
run:
Trying to Remove JDialog
Remove Cycle Done :-)
Checking if still exists any of TopLayoutContainers
JFrame
JDialog
Will Try Remove Dialog again, CycleNo. 1
-----------------------------------------------------------
Trying to Remove JDialog
Remove Cycle Done :-)
Checking if still exists any of TopLayoutContainers
JFrame
JDialog
Will Try Remove Dialog again, CycleNo. 2
-----------------------------------------------------------
Trying to Remove JDialog
Remove Cycle Done :-)
Checking if still exists any of TopLayoutContainers
JFrame
JDialog
Will Try Remove Dialog again, CycleNo. 3
-----------------------------------------------------------
Trying to Remove JDialog
Remove Cycle Done :-)
Checking if still exists any of TopLayoutContainers
JFrame
JDialog
*** End of Cycle Without Success, Exit App ***
BUILD SUCCESSFUL (total time: 13 seconds)
我将再次尝试问这个问题:How can I kil*l on Runtime the first-opened top-Level Container
, and help为我结束一场《Swing NightMares》?
import java.awt.*;
import java.awt.event.WindowEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class RemoveDialogOnRuntime extends JFrame {
private static final long serialVersionUID = 1L;
private int contID = 1;
private boolean runProcess;
private int top = 20;
private int left = 20;
private int maxLoop = 0;
public RemoveDialogOnRuntime() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(300, 300));
setTitle("Remove Dialog On Runtime");
setLocation(150, 150);
pack();
setVisible(true);
Point loc = this.getLocation();
top += loc.x;
left += loc.y;
AddNewDialog();
}
private void AddNewDialog() {
DialogRemove firstDialog = new DialogRemove();
remWins();
}
private void remWins() {
runProcess = true;
Thread th = new Thread(new RemTask());
th.setDaemon(false);
th.setPriority(Thread.MIN_PRIORITY);
th.start();
}
private class RemTask implements Runnable {
@Override
public void run() {
while (runProcess) {
Window[] wins = Window.getWindows();
for (int i = 0; i < wins.length; i++) {
if (wins[i] instanceof JDialog) {
System.out.println(" Trying to Remove JDialog");
wins[i].setVisible(false);
wins[i].dispose();
WindowEvent windowClosing = new WindowEvent(wins[i], WindowEvent.WINDOW_CLOSING);
wins[i].dispatchEvent(windowClosing);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(windowClosing);
Runtime runtime = Runtime.getRuntime();
runtime.gc();
runtime.runFinalization();
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(RemoveDialogOnRuntime.class.getName()).log(Level.SEVERE, null, ex);
}
}
wins = null;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println(" Remove Cycle Done :-)");
Runtime.getRuntime().runFinalization();
Runtime.getRuntime().gc();
runProcess = false;
}
});
}
pastRemWins();
}
}
private void pastRemWins() {
System.out.println(" Checking if still exists any of TopLayoutContainers");
Window[] wins = Window.getWindows();
for (int i = 0; i < wins.length; i++) {
if (wins[i] instanceof JFrame) {
System.out.println("JFrame");
wins[i].setVisible(true);
} else if (wins[i] instanceof JDialog) {
System.out.println("JDialog");
wins[i].setVisible(true);
}
}
if (wins.length > 1) {
wins = null;
maxLoop++;
if (maxLoop <= 3) {
System.out.println(" Will Try Remove Dialog again, CycleNo. " + maxLoop);
System.out.println(" -----------------------------------------------------------");
remWins();
} else {
System.out.println(" -----------------------------------------------------------");
System.out.println("*** End of Cycle Without Success, Exit App ***");
closeMe();
}
}
}
private void closeMe() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
System.exit(0);
}
});
}
private class DialogRemove extends JDialog {
private static final long serialVersionUID = 1L;
DialogRemove(final Frame parent) {
super(parent, "SecondDialog " + (contID++));
setLocation(top, left);
top += 20;
left += 20;
setPreferredSize(new Dimension(200, 200));
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModalityType(Dialog.ModalityType.MODELESS);
pack();
setVisible(true);
}
private DialogRemove() {
setTitle("SecondDialog " + (contID++));
setLocation(top, left);
top += 20;
left += 20;
setPreferredSize(new Dimension(200, 200));
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModalityType(Dialog.ModalityType.MODELESS);
pack();
setVisible(true);
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
RemoveDialogOnRuntime superConstructor = new RemoveDialogOnRuntime();
}
});
}
}
Unfortunately, it looks like this recently closed question was not well understood. Here is the typical output:
run:
Trying to Remove JDialog
Remove Cycle Done :-)
Checking if still exists any of TopLayoutContainers
JFrame
JDialog
Will Try Remove Dialog again, CycleNo. 1
-----------------------------------------------------------
Trying to Remove JDialog
Remove Cycle Done :-)
Checking if still exists any of TopLayoutContainers
JFrame
JDialog
Will Try Remove Dialog again, CycleNo. 2
-----------------------------------------------------------
Trying to Remove JDialog
Remove Cycle Done :-)
Checking if still exists any of TopLayoutContainers
JFrame
JDialog
Will Try Remove Dialog again, CycleNo. 3
-----------------------------------------------------------
Trying to Remove JDialog
Remove Cycle Done :-)
Checking if still exists any of TopLayoutContainers
JFrame
JDialog
*** End of Cycle Without Success, Exit App ***
BUILD SUCCESSFUL (total time: 13 seconds)
I'll try asking this question again: How can I kil*l on Runtime the first-opened top-Level Container
, and help with closing for me one of Swing NightMares?
import java.awt.*;
import java.awt.event.WindowEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class RemoveDialogOnRuntime extends JFrame {
private static final long serialVersionUID = 1L;
private int contID = 1;
private boolean runProcess;
private int top = 20;
private int left = 20;
private int maxLoop = 0;
public RemoveDialogOnRuntime() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(300, 300));
setTitle("Remove Dialog On Runtime");
setLocation(150, 150);
pack();
setVisible(true);
Point loc = this.getLocation();
top += loc.x;
left += loc.y;
AddNewDialog();
}
private void AddNewDialog() {
DialogRemove firstDialog = new DialogRemove();
remWins();
}
private void remWins() {
runProcess = true;
Thread th = new Thread(new RemTask());
th.setDaemon(false);
th.setPriority(Thread.MIN_PRIORITY);
th.start();
}
private class RemTask implements Runnable {
@Override
public void run() {
while (runProcess) {
Window[] wins = Window.getWindows();
for (int i = 0; i < wins.length; i++) {
if (wins[i] instanceof JDialog) {
System.out.println(" Trying to Remove JDialog");
wins[i].setVisible(false);
wins[i].dispose();
WindowEvent windowClosing = new WindowEvent(wins[i], WindowEvent.WINDOW_CLOSING);
wins[i].dispatchEvent(windowClosing);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(windowClosing);
Runtime runtime = Runtime.getRuntime();
runtime.gc();
runtime.runFinalization();
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(RemoveDialogOnRuntime.class.getName()).log(Level.SEVERE, null, ex);
}
}
wins = null;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println(" Remove Cycle Done :-)");
Runtime.getRuntime().runFinalization();
Runtime.getRuntime().gc();
runProcess = false;
}
});
}
pastRemWins();
}
}
private void pastRemWins() {
System.out.println(" Checking if still exists any of TopLayoutContainers");
Window[] wins = Window.getWindows();
for (int i = 0; i < wins.length; i++) {
if (wins[i] instanceof JFrame) {
System.out.println("JFrame");
wins[i].setVisible(true);
} else if (wins[i] instanceof JDialog) {
System.out.println("JDialog");
wins[i].setVisible(true);
}
}
if (wins.length > 1) {
wins = null;
maxLoop++;
if (maxLoop <= 3) {
System.out.println(" Will Try Remove Dialog again, CycleNo. " + maxLoop);
System.out.println(" -----------------------------------------------------------");
remWins();
} else {
System.out.println(" -----------------------------------------------------------");
System.out.println("*** End of Cycle Without Success, Exit App ***");
closeMe();
}
}
}
private void closeMe() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
System.exit(0);
}
});
}
private class DialogRemove extends JDialog {
private static final long serialVersionUID = 1L;
DialogRemove(final Frame parent) {
super(parent, "SecondDialog " + (contID++));
setLocation(top, left);
top += 20;
left += 20;
setPreferredSize(new Dimension(200, 200));
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModalityType(Dialog.ModalityType.MODELESS);
pack();
setVisible(true);
}
private DialogRemove() {
setTitle("SecondDialog " + (contID++));
setLocation(top, left);
top += 20;
left += 20;
setPreferredSize(new Dimension(200, 200));
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModalityType(Dialog.ModalityType.MODELESS);
pack();
setVisible(true);
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
RemoveDialogOnRuntime superConstructor = new RemoveDialogOnRuntime();
}
});
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
调用
dispose( )
允许主机平台回收重量级对等方消耗的内存,但只有在处理WINDOW_CLOSING
事件之后才能这样做在EventQueue
。即使如此,gc()
仍然是一个建议。附录:查看噩梦的另一种方法是通过分析器。使用
jvisualvm
运行下面的示例,可以看到定期收集永远不会完全返回到基线。我从人为的小堆开始夸大了垂直轴。显示了其他示例 这里。当内存非常有限时,我使用了两种方法:紧急:从命令行循环,每次启动一个新虚拟机。
紧急:完全消除重量级组件,无头运行并仅使用 2D 图形和轻量级组件在
BufferedImage
中组合。Invoking
dispose()
allows the host platform to reclaim memory consumed by the heavyweight peer, but it can't do so until after theWINDOW_CLOSING
event is processed on theEventQueue
. Even then,gc()
is a suggestion.Addendum: Another way to see the nightmare is via a profiler. Running the example below with
jvisualvm
, one can see that periodic collection never quite returns to baseline. I've exaggerated the vertical axis by starting with an artificially small heap. Additional examples are shown here. When memory is very limited, I've used two approaches:Emergent: Loop from the command line, starting a new VM each time.
Urgent: Eliminate the heavyweight component entirely, running headless and composing in a
BufferedImage
using 2D graphics and lightweight components only.我已经完全修改了您的示例:
setLocation()
,未使用的构造函数...)Thread
(在EDT中不是一个好主意)Window.getWindows()
是否为2 (不是 1),因为在 Swing 中,如果您打开一个没有父级的对话框,那么将创建一个特殊的不可见框架来将其用作父级(实际上对于所有无主对话框),一旦创建,该框架无法删除。生成的代码片段如下:
重要的结论是:
Window.getWindows()< 中删除已处置的对话框/code> (这个对我来说看起来像是一个 bug,但我认为原因是 Swing 为所有窗口保留了一个
WeakReference
,并且这个WeakReference
在 GC 之前不会释放 已经发生了。希望这 为您的问题提供清晰完整的答案。
I have completely reworked your example:
setLocation()
, unused constructor...)javax.swing.Timer
instead of aThread
for disposing of the dialogThread
for forcing GC (not a good idea in the EDT)Window.getWindows()
is 2 (not 1), because in Swing, if you open a dialog with no parent, then a special invisible frame will be created to use it as parent (for all ownerless dialogs actually), once created, that frame cannot be removed.The resulting snippet follows:
The important conclusions are:
Window.getWindows()
(that one looks like a bug to me but I think the reason is that Swing keeps aWeakReference
to all windows, and thisWeakReference
is not released until a GC has occurred.Hope this gives a clear and complete answer to your problem.
目的是消除对 EDT 的所有疑虑并确认 Trashgod 更新的建议,然后
从代码输出到控制台
with the intent to blow away all doubts about EDT and confirm trashgod Updated suggestion, then output to the console is
from code
我不确定您的问题是关于“垃圾收集”还是关于如何识别可见的对话框。
您无法控制垃圾收集何时完成。调用 gc() 方法只是一个建议。
如果您想忽略“已处理”对话框,则可以使用 isDisplayable() 方法来检查其状态。
通过以下程序,我得到了一些有趣的结果。我所做的第一个更改是向对话框添加一些组件,以便每个对话框使用更多资源,这将增加资源被垃圾收集的机会。
在我的机器上,我发现如果我
a) 创建 5 个对话框
b) 关闭对话框
c) 创建 5 个对话框
然后前 5 个对话框似乎已被垃圾收集。
但是,如果我创建 5,然后关闭,然后创建 1,然后关闭,它似乎不起作用。
最重要的是,您不能依赖垃圾收集何时完成,因此我建议您使用 isDisplayable() 方法来确定如何进行处理。 “显示对话框”按钮使用此方法作为显示输出的一部分。
I'm not sure if you question is about "garbage collection" or about how to identify dialogs that are visible.
You can't control when garbage collection is done. Invoking the gc() method is only a suggestion.
If you want to ignore "disposed" dialogs then you can use the isDisplayable() method to check its status.
With the following program I got some interesting results. First change I made was to add some components to the dialog so that more resources would be used for each dialog which would increase the chance that the resources would be garbage collected.
On my machine I found that if I
a) create 5 dialogs
b) close the dialogs
c) create 5 dialogs
Then the first 5 appear to be garbage collected.
However if I create 5, then close then create 1, then close, it doesn't seem to work.
Bottom line is you can't depend on when garbage collection will be done, so I suggest you use the isDisplayable() method to determine how to do your processing. The "Display Dialogs" button uses this method as part of the displayed output.
在某些资源最终被释放之前,
AppContext
中定义了一个超时时间。该时间设置为 5 秒左右。因此,如果您再等待五秒钟,上下文也会处理对对话框的(最后一个)引用。There is a timeout defined in the
AppContext
before some resources will be released finally. This is set to something like 5 seconds. Thus if you wait for another five seconds also the context will dispose the (last) reference to your dialog.