【问题标题】:Remove Top-Level Container on Runtime在运行时删除顶级容器
【发布时间】:2011-09-12 15:46:24
【问题描述】:

不幸的是,最近关闭的question 似乎没有得到很好的理解。这是典型的输出:

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)

我会再次尝试问这个问题:我如何在 Runtime 上了解第一个打开的顶级 Container,并帮助我关闭 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();
            }
        });
    }
}

【问题讨论】:

  • @mKorbel,就像我之前所说的,将引用设置为null,那么它将有资格进行垃圾收集。
  • @mre :-) 我非常感谢您在我之前的帖子中为删除对 Array 的引用所做的输入,并尝试通过 Object 从 Class(es) 中删除它,但仍然存在一个 JDialog 和一个 JWindow ... :-)
  • 您的示例代码违反了“EDT 黄金法则”:永远不要从除 EDT 之外的其他线程调用 Swing 方法。当您调用 dispose() 时,您不在 EDT 中! pastRemWins() 中 setVisible() 的注释相同。
  • 如果您可以通过“删除容器”来指定您的意思,例如,您的问题会更清楚。删除窗口的操作系统资源,隐藏窗口,收集窗口使用的 Java 对象使用的内存...
  • dispose() 明确记录为释放窗口使用的所有操作系统资源,因此不是它的 java 部分! Javadoc 甚至提到调用pack()setVisible(true) 将重新创建新的操作系统资源以使窗口可显示。

标签: java swing runtime jdialog


【解决方案1】:

调用dispose() 允许主机平台回收重量级对等点消耗的内存,但直到在EventQueue 上处理WINDOW_CLOSING 事件之后 才能这样做。即使这样,gc() 也是一个建议。

附录:查看噩梦的另一种方法是通过分析器。使用jvisualvm 运行下面的示例,可以看到定期收集永远不会相当 返回基线。我从一个人为的小堆开始夸大了垂直轴。其他示例显示在here。当内存非常有限时,我使用了两种方法:

  • 紧急:从命令行循环,每次启动一个新虚拟机。

  • 紧急:完全消除重量级组件,无头运行并仅使用 2D 图形和轻量级组件在 BufferedImage 中编写。

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.WindowEvent;
import javax.swing.JDialog;

/** @see https://stackoverflow.com/questions/6309407 */
public class DialogClose extends JDialog {

    public DialogClose(int i) {
        this.setTitle("Dialog " + String.valueOf(i));
        this.setPreferredSize(new Dimension(320, 200));
    }

    private void display() {
        this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
        passSomeTime();
        this.setVisible(false);
        this.dispatchEvent(new WindowEvent(
            this, WindowEvent.WINDOW_CLOSING));
        this.dispose();
        passSomeTime();
    }

    private void passSomeTime() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException ie) {
            ie.printStackTrace(System.err);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                int count = 0;
                while (true) {
                    new DialogClose(count++).display();
                }
            }
        });
    }
}

【讨论】:

    【解决方案2】:

    我已经完全修改了你的例子:

    • 我已经简化了不需要的部分(setLocation(),未使用的构造函数...)
    • 我已经删除了触发 WINDOW_CLOSING 事件的代码(没用)
    • 我已删除将所有窗口重新设置为可见的代码(这将阻止对它们进行 GC)
    • 我使用javax.swing.Timer 而不是Thread 来处理对话框
    • 我使用了 Thread 来强制 GC(在 EDT 中不是一个好主意)
    • 我已修改最终成功标准以检查 Window.getWindows() 是否为 2(不是 1),因为在 Swing 中,如果您打开没有父级的对话框,然后将创建一个特殊的不可见框架以将其用作父级(实际上对于所有无主对话框),一旦创建,该框架不能被删除。

    生成的 sn-p 如下:

    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.*;
    
    public class RemoveDialogOnRuntime extends JFrame {
    
        private static final long serialVersionUID = 1L;
        private boolean runProcess;
        private int maxLoop = 0;
        private Timer timer;
    
        public RemoveDialogOnRuntime() {
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setPreferredSize(new Dimension(300, 300));
            setTitle("Remove Dialog On Runtime");
            setLocation(150, 150);
            pack();
            setVisible(true);
            addNewDialog();
        }
    
        private void addNewDialog() {
            DialogRemove firstDialog = new DialogRemove();
            remWins();
        }
    
        private void remWins() {
            runProcess = true;
            timer = new Timer(1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (runProcess) {
                        for (Window win: Window.getWindows()) {
                            if (win instanceof JDialog) {
                                System.out.println("    Trying to Remove JDialog");
                                win.dispose();
                            }
                        }
                        System.out.println("    Remove Cycle Done :-)");
                        runProcess = false;
                        new Thread() {
                            @Override
                            public void run() {
                                try {
                                    Thread.sleep(100);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                Runtime.getRuntime().gc();
                            }
                        }.start();
                    } else {
                        pastRemWins();
                        runProcess = true;
                    }
                }
            });
            timer.setRepeats(true);
            timer.start();
        }
    
        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");
                } else if (wins[i] instanceof JDialog) {
                    System.out.println("JDialog");
                } else {
                    System.out.println(wins[i].getClass().getSimpleName());
                }
            }
            // We must expect 2 windows here: this (RemoveDialogOnRuntime) and the parent of all parentless dialogs
            if (wins.length > 2) {
                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();
                }
            } else {
                timer.stop();
            }
        }
    
        private void closeMe() {
            System.exit(0);
        }
    
        private class DialogRemove extends JDialog {
    
            private static final long serialVersionUID = 1L;
    
            private DialogRemove() {
                setTitle("SecondDialog");
                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();
                }
            });
        }
    }
    

    重要的结论是:

    • 您无法删除 Swing 创建的不可见框架作为所有无主对话框的父级
    • 您必须强制 GC 才能从 Window.getWindows() 中删除已处理的对话框(这对我来说似乎是一个错误,但我认为原因是 Swing 为所有窗口保留了一个 WeakReference,而这个 @987654329 @ 在 GC 发生之前不会被释放。

    希望这可以为您的问题提供清晰完整的答案。

    【讨论】:

    • 感谢您的宝贵意见 1+,一切都清楚了,但是在删除无用的方法后,您失去了从 UsedMemory 级别的顶级容器中删除 2D 图形的效果(由垃圾神),确定仍然存在另一个选项如何减少使用的内存,JDialog#WINDOW_CLOSING 加上 JDialog#removeAll == remove RootPane :-) 然后 JDialog (JWindow) 的内容将是半透明的:-),结果仍然保留在 Java6 中的任何 Top_layoput 是可能的,仅删除 2D 图形,谢谢
    【解决方案3】:

    为了消除对 EDT 的所有疑虑并确认垃圾神更新的建议,然后输出到控制台是

    run:
    7163 KB used before GC
        Trying to Remove JDialog
        Remove Cycle Done :-)
    405 KB used after GC
        Checking if still exists any of TopLayoutContainers
    JFrame
    JDialog
        Will Try Remove Dialog again, CycleNo. 1
     -----------------------------------------------------------
    3274 KB used before GC
        Trying to Remove JDialog
        Remove Cycle Done :-)
    403 KB used after GC
        Checking if still exists any of TopLayoutContainers
    JFrame
    JDialog
        Will Try Remove Dialog again, CycleNo. 2
     -----------------------------------------------------------
    3271 KB used before GC
        Trying to Remove JDialog
        Remove Cycle Done :-)
    406 KB used after GC
        Checking if still exists any of TopLayoutContainers
    JFrame
    JDialog
        Will Try Remove Dialog again, CycleNo. 3
     -----------------------------------------------------------
    3275 KB used before GC
        Trying to Remove JDialog
        Remove Cycle Done :-)
    403 KB used after GC
        Checking if still exists any of TopLayoutContainers
    JFrame
    JDialog
     -----------------------------------------------------------
    *** End of Cycle Without Success, Exit App ***
    BUILD SUCCESSFUL (total time: 26 seconds) 
    

    来自代码

    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.WindowEvent;
    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;
        private javax.swing.Timer timer = null;
    
        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() {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    DialogRemove firstDialog = new DialogRemove();
                    startAA();
                }
            });
        }
    
        private void startAA() {
            timer = new javax.swing.Timer(5000, updateAA());
            timer.setRepeats(false);
            timer.start();
        }
    
        public Action updateAA() {
            return new AbstractAction("text load action") {
    
                private static final long serialVersionUID = 1L;
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    timer.stop();
                    if (SwingUtilities.isEventDispatchThread()) {
                        Runnable doRun = new Runnable() {
    
                            @Override
                            public void run() {
                                remWins();
                            }
                        };
                        SwingUtilities.invokeLater(doRun);
                    } else {
                        Runnable doRun = new Runnable() {
    
                            @Override
                            public void run() {
                                remWins();
                            }
                        };
                        SwingUtilities.invokeLater(doRun);
                    }
                }
            };
        }
    
        private void remWins() {
            Runtime runtime = Runtime.getRuntime();
            long total = runtime.totalMemory();
            long free = runtime.freeMemory();
            long max = runtime.maxMemory();
            long used = total - free;
            System.out.println(Math.round(used / 1e3) + " KB used before GC");
            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.getRuntime();
                    runtime.gc();
                    runtime.runFinalization();
                }
            }
            wins = null;
            System.out.println("    Remove Cycle Done :-)");
            runtime.runFinalization();
            runtime.gc();
            runtime = Runtime.getRuntime();
            total = runtime.totalMemory();
            free = runtime.freeMemory();
            max = runtime.maxMemory();
            used = total - free;
            System.out.println(Math.round(used / 1e3) + " KB used after GC");
            startOO();
        }
    
        private void startOO() {
            timer = new javax.swing.Timer(5000, updateOO());
            timer.setRepeats(false);
            timer.start();
        }
    
        public Action updateOO() {
            return new AbstractAction("text load action") {
    
                private static final long serialVersionUID = 1L;
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    timer.stop();
                    timer.stop();
                    if (SwingUtilities.isEventDispatchThread()) {
                        Runnable doRun = new Runnable() {//really contraproductive just dealayed
    
                            @Override
                            public void run() {
                                pastRemWins();
                            }
                        };
                        SwingUtilities.invokeLater(doRun);
                    } else {
                        Runnable doRun = new Runnable() {
    
                            @Override
                            public void run() {
                                pastRemWins();
                            }
                        };
                        SwingUtilities.invokeLater(doRun);
                    }
                }
            };
        }
    
        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();
                }
            }
            startAA();
        }
    
        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();
                }
            });
        }
    }
    

    【讨论】:

    • +1 在 JVM 退出之前无法可靠地回收重量级组件的内存是有道理的。
    【解决方案4】:

    我不确定您的问题是关于“垃圾收集”还是关于如何识别可见的对话框。

    您无法控制垃圾回收何时完成。调用 gc() 方法只是一个建议。

    如果你想忽略“disposed”对话框,那么你可以使用 isDisplayable() 方法来检查它的状态。

    通过以下程序,我得到了一些有趣的结果。我所做的第一个更改是在对话框中添加一些组件,以便为每个对话框使用更多资源,这将增加资源被垃圾收集的机会。

    在我的机器上,我发现如果我

    a) 创建 5 个对话框
    b) 关闭对话框
    c) 创建 5 个对话框

    那么前 5 个似乎被垃圾回收了。

    但是,如果我创建 5,然后关闭,然后创建 1,然后关闭,它似乎不起作用。

    底线是你不能依赖垃圾收集何时完成,所以我建议你使用 isDisplayable() 方法来确定如何进行处理。 “显示对话框”按钮使用此方法作为显示输出的一部分。

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class DialogSSCCE extends JPanel
    {
        public static int count;
    
        public DialogSSCCE()
        {
            JButton display = new JButton("Display Dialogs");
            display.addActionListener( new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    System.out.println();
                    System.out.println("Display Dialogs");
    
                    for (Window window: Window.getWindows())
                    {
                        if (window instanceof JDialog)
                        {
                            JDialog dialog = (JDialog)window;
                            System.out.println("\t" + dialog.getTitle() + " " + dialog.isDisplayable());
                        }
                    }
                }
            });
            add( display );
    
            JButton open = new JButton("Create Dialog");
            open.addActionListener( new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    System.out.println();
                    System.out.println("Create Dialog");
    
                    JDialog dialog = new JDialog();
                    dialog.getContentPane().setLayout(null);
    
                    for (int i = 0; i < 200; i++)
                    {
                        dialog.add( new JTextField("some text") );
                    }
    
                    dialog.setTitle("Dialog " + count++);
                    dialog.setLocation(count * 25, count * 25);
                    dialog.setVisible(true);
                    System.out.println("\tCreated " + dialog.getTitle());
                }
            });
            add( open );
    
            JButton close = new JButton("Close Dialogs");
            close.addActionListener( new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    System.out.println();
                    System.out.println("Close Dialogs");
    
                    for (Window window: Window.getWindows())
                    {
                        if (window instanceof JDialog)
                        {
                            JDialog dialog = (JDialog)window;
                            System.out.println("\tClosing " + dialog.getTitle());
                            dialog.dispose();
                        }
                    }
    
                    Runtime.getRuntime().gc();
                }
            });
            add( close );
        }
    
        private static void createAndShowUI()
        {
            JFrame frame = new JFrame("DialogSSCCE");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add( new DialogSSCCE() );
            frame.pack();
            frame.setLocationRelativeTo( null );
            frame.setVisible( true );
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowUI();
                }
            });
        }
    }
    

    【讨论】:

      【解决方案5】:

      AppContext 中定义了一个超时时间,最终将释放一些资源。这设置为大约 5 秒。因此,如果您再等待 5 秒钟,上下文也会处理(最后)对您的对话框的引用。

      wins = null;
      Thread.sleep(5000);
      

      【讨论】:

      • 似乎没有任何改变,我尝试了所有可能的woodoo ... :-) +1,真的,如果你要创建多个JDialog,每个都被gc杀死,首先保持活力(对于JWindow),如果你要创建大量的 JDialogs 和 JWindows,那么每个 JDialogs 和 JWindows 都会被处理和 GC,但首先 JDialogs 和 JWindows 也将永远存在:-),eeerrrggghhhht...
      • @mKorbel 它确实释放了我测试中的最后一个窗口,只剩下 JFrame。加上一个额外的隐藏框架,您不会在循环中打印。因此 wins.length 仍然是两个!
      猜你喜欢
      • 1970-01-01
      • 2018-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-24
      • 2016-10-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多