Удалить контейнер верхнего уровня во время выполнения

К сожалению, похоже, что это недавно закрыто вопрос не был хорошо понят. Вот типичный вывод:

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)

Я попробую задать этот вопрос еще раз: как я могу kil*l во время выполнения первого открытого верхнего уровня 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();
            }
        });
    }
}

person mKorbel    schedule 10.06.2011    source источник
comment
@mKorbel, как я уже говорил, установите ссылку на null, тогда она будет допущена к сборке мусора.   -  person mre    schedule 10.06.2011
comment
@mre :-) Я очень ценю ваш вклад в моем предыдущем сообщении об удалении ссылки на массив и пытался удалить его с помощью объекта из класса (ов), но все еще существуют один JDialog и один JWindow ... :-)   -  person mKorbel    schedule 10.06.2011
comment
@mre Я не могу установить ссылку на null только дважды wins = null;   -  person mKorbel    schedule 10.06.2011
comment
Я не кодер и не разработчик, просто фанаты Java, которые не смогли принять, утверждают, что первый JDialog (плюс JWindow, если отображается) все еще существует в среде выполнения, и я не могу его удалить (для этой цели я купил на прошлой неделе OneRitchUnNamed JavaTools тоже никак, теперь я пытаюсь решить это стандартным способом)   -  person mKorbel    schedule 10.06.2011
comment
Почему вы пытаетесь это сделать?   -  person meverett    schedule 10.06.2011
comment
+1 У меня был тот же кошмар, когда я запускал тяжеловесные приложения в цикле из командной строки.   -  person trashgod    schedule 10.06.2011
comment
@trashgod спасибо за изменение, ничего не упустил :-) +1, @camickr спасибо за хороший совет +1, как я пробовал, мой код работает для контейнеров верхнего уровня только в том случае, если есть более одного JDialog или JWindow, сначала добавил контейнер довольно игнорируется, :-)   -  person mKorbel    schedule 11.06.2011
comment
Ваш пример кода нарушает золотое правило EDT: никогда не вызывайте метод Swing из другого потока, кроме EDT. Когда вы вызываете dispose(), вы не находитесь в EDT! То же замечание для setVisible() в pastRemWins().   -  person jfpoilpret    schedule 11.06.2011
comment
Ваш вопрос был бы более ясным, если бы вы могли указать, что вы имеете в виду, удаляя контейнер, например. удалить ресурсы ОС для окна, сделать окно скрытым, собрать память, используемую объектами Java, используемыми окном...   -  person jfpoilpret    schedule 11.06.2011
comment
dispose() четко задокументировано как освобождение всех ресурсов ОС, используемых окном, и, следовательно, НЕ его java-части! Javadoc даже упоминает, что вызов pack() или setVisible(true) будет воссоздавать новые ресурсы ОС, чтобы сделать окно отображаемым.   -  person jfpoilpret    schedule 11.06.2011
comment
@jfpoilpret, пожалуйста, посмотрите мой ответ на сообщение Говарда, в любом случае, если у вас есть какой-либо хак, пожалуйста, опубликуйте здесь свое мнение, потому что в этом случае я почти уверен, что EDT должно быть нарушено, я пробовал это, иначе эффекты переменны, иногда оставайтесь в живых два JDialogs, иногда только один, я действительно не знаю, первый JDialog останется в живых навсегда...   -  person mKorbel    schedule 11.06.2011
comment
@mKorbel смотрите мой недавно опубликованный ответ, который не должен нарушать какие-либо правила EDT.   -  person jfpoilpret    schedule 16.06.2011


Ответы (5)


Вызов dispose() позволяет хост-платформе восстановить память, потребляемую тяжеловесным одноранговым узлом, но она не может этого сделать до тех пор, пока после события WINDOW_CLOSING не будет обработано на EventQueue. Даже тогда gc() является предложением.

Приложение: Еще один способ увидеть кошмар — через профайлер. Запустив приведенный ниже пример с jvisualvm, можно увидеть, что периодический сбор никогда полностью не возвращается к исходному уровню. Я преувеличил вертикальную ось, начав с искусственно маленькой кучи. Показаны дополнительные примеры /5918785#5918785">здесь. Когда память очень ограничена, я использовал два подхода:

  • Emergent: Цикл из командной строки, каждый раз запуская новую виртуальную машину.

  • Срочно: полностью устраните тяжелый компонент, работайте без головы и составляйте в BufferedImage, используя только 2D-графику и легкие компоненты.

введите здесь описание изображения

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();
                }
            }
        });
    }
}
person trashgod    schedule 10.06.2011

Я полностью переработал ваш пример:

  • Я упростил то, что было не нужно (setLocation(), неиспользуемый конструктор...)
  • Я удалил код, запускающий событие WINDOW_CLOSING (бесполезно)
  • Я удалил код, который снова сбрасывает все окна в видимые (что предотвратило бы их сборку мусора)
  • Я использовал javax.swing.Timer вместо Thread для удаления диалога
  • Я использовал Thread для форсирования GC (не очень хорошая идея в EDT)
  • Я изменил окончательный критерий успеха, чтобы проверить, что Window.getWindows() равно 2 (а не 1), потому что в Swing, если вы открываете диалоговое окно без родителя, то появляется специальный невидимый фрейм. будет создан, чтобы использовать его в качестве родителя (фактически для всех бесхозных диалогов), после создания этот фрейм нельзя удалить.

Полученный фрагмент выглядит следующим образом:

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 для всех окон, и этот WeakReference не выпускается до тех пор, пока не произойдет GC .

Надеюсь, что это дает четкий и полный ответ на вашу проблему.

person jfpoilpret    schedule 16.06.2011
comment
спасибо за ваш ценный вклад 1+, все ясно, но после удаления бесполезных методов вы потеряли эффект от удаления 2D-графики из контейнеров верхнего уровня на уровне UsedMemory (от trashgod), уверен, что все еще существует другой вариант, как уменьшить используемую память, JDialog#WINDOW_CLOSING плюс JDialog#removeAll == удалить RootPane :-) тогда содержимое JDialog (JWindow) будет полупрозрачным :-), результат останется в Java6 из любого Top_layoput возможно удалить только 2D Graphics, спасибо - person mKorbel; 16.06.2011

с намерением развеять все сомнения по поводу EDT и подтвердить обновленное предложение TrashGod, затем вывод на консоль

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();
            }
        });
    }
}
person mKorbel    schedule 11.06.2011
comment
+1 Есть смысл в том, что память для тяжеловесных компонентов не может быть надежно восстановлена ​​до выхода JVM. - person trashgod; 12.06.2011

Я не уверен, что вы спрашиваете о «сборке мусора» или о том, как идентифицировать видимые диалоги.

Вы не можете контролировать, когда выполняется сборка мусора. Вызов метода gc() является только предложением.

Если вы хотите игнорировать «удаленные» диалоги, вы можете использовать метод isDisplayable() для проверки его статуса.

Со следующей программой я получил некоторые интересные результаты. Первым изменением, которое я внес, было добавление некоторых компонентов в диалоговое окно, чтобы для каждого диалогового окна использовалось больше ресурсов, что увеличило вероятность того, что ресурсы будут удалены сборщиком мусора.

На моей машине я обнаружил, что если я

а) создать 5 диалогов
б) закрыть диалоги
в) создать 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();
            }
        });
    }
}
person camickr    schedule 10.06.2011

В AppContext определен тайм-аут, прежде чем некоторые ресурсы будут окончательно освобождены. Это установлено примерно на 5 секунд. Таким образом, если вы подождете еще пять секунд, контекст также будет располагать (последней) ссылкой на ваш диалог.

wins = null;
Thread.sleep(5000);
person Howard    schedule 11.06.2011
comment
вроде ничего не изменилось, перепробовал все возможные вуду... :-) +1, действительно если будешь создавать более одного JDialog каждый будет убит gc, сначала останься в живых (то же самое для JWindow), если создашь тонны JDialogs и JWindows, затем все удаляются и подвергаются сборке мусора, но в первую очередь JDialogs и JWindows тоже остаются жить вечно :-), eeerrrggghhhht... - person mKorbel; 11.06.2011
comment
@mKorbel Это действительно освободило последнее окно в моем тесте, и остался только JFrame. Плюс дополнительный скрытый кадр, который вы не печатаете в своем цикле. Таким образом, wins.length по-прежнему равно двум! - person Howard; 11.06.2011