сборка мусора Java в диалоге

* Сейчас я сталкиваюсь с очень странной проблемой Java GC, когда пытаюсь создать кнопку в JFrame, и когда я нажимаю кнопку, она отображает JDialog, который должен иметь дело с некоторыми изображениями и требовать около 200 м. объем памяти. Но проблема в том, что когда я закрываю диалог и снова открываю его, иногда это вызывает java.lang.OutOfMemoryError. (не каждый раз)

Пытаясь решить проблему, я упрощаю эту проблему и провожу некоторый эксперимент, , который вызывает у меня большую путаницу.

Код, который я использовал в своем «эксперименте», показан ниже. Когда я нажимаю кнопку в кадре, я выделяю 160M памяти для целочисленного массива и отображаю диалоговое окно, Но если я закрываю диалоговое окно и открываю его снова, появляется OutOfMemoryError. Я корректирую код и результат является:

  1. Если я не создаю диалоговое окно и не показываю его, проблем с памятью нет.
  2. Если я добавлю windowsCloseListener, который вызывает System.gc () к диалоговому окну, проблем с памятью нет.
  3. Если я вызываю System.gc () в методе run (), возникает проблема с памятью.

    public class TestController {
      int[] tmp;
    
      class TDialog extends JDialog {
        public TDialog() {
          super();
          this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
          // If I uncommment this code, OutOfMemoryError seems to dispear in this situation
          // But I'm sure it not a acceptable solution
          /*
          this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
              System.out.println("windowsclose");
              TDialog.this.dispose();
              System.gc();
            }
          });
          */
        }
      }
    
      TDialog dia;
    
      public void run() {
        // If I do System.gc() here, OutOfMemoryError still exist
        // System.gc();
        tmp = new int[40000000];
        for (int i = 0; i < tmp.length; i += 10)
          tmp[i] = new Random().nextInt();
    
        dia = new TDialog();
        dia.setVisible(true);
      }
    
      public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
          @Override
          public void run() {
            final JFrame frame = new JFrame("test");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.setLocationRelativeTo(null);
            frame.setSize(200, 200);
    
            JButton button = new JButton("button");
            button.addActionListener(new ActionListener() {
              @Override
              public void actionPerformed(ActionEvent e) {
                TestController controller = new TestController();
                controller.run();
                controller = null;
              }
            });
    
            frame.add(button);
            frame.setVisible(true);
          }
        });
      }
    }
    

Я читал о многих статьях, в которых описывается, как работает Java-сборщик мусора. Я думаю, что если Java пытается выделить некоторое пространство в куче, и у него недостаточно свободного места, java сделает gc, и если к объекту нельзя получить доступ из корня gc через «граф GC», в котором ребро из от u до v у вас есть ссылка на v, root - это что-то в рабочем стеке потоков или нативных ресурсах. Это бесполезно и квалифицировано для сбора в GC java.

Теперь проблема в том, что , когда я нажимаю кнопку и пытаюсь создать массив Integer, массив Integer, который я создаю в прошлый раз, безусловно, пригоден для сбора в GC Java. Так почему это вызвало ошибку.

Прошу прощения за такое длинное описание ... У меня нет особой тактики в постановке проблемы, поэтому просто пытаюсь прояснить ее.

Кроме того, для запуска jvm я использовал параметр «java –Xmx256m»

7 голосов | спросил ryanaaa 25 +04002013-10-25T23:24:07+04:00312013bEurope/MoscowFri, 25 Oct 2013 23:24:07 +0400 2013, 23:24:07

2 ответа


0

Вы выделяете new int[40000000] раньше, пока tmp по-прежнему содержит ссылку на последний int[40000000].
Порядок работы в выражении типа tmp = new int[40000]:

    new int[40000] литий>
  1. Назначьте ссылку на массив в tmp

Таким образом, в 1. tmp все еще содержится ссылка на его последнее значение.

Попробуйте сделать:

tmp = null;
tmp = new int[40000000];
ответил rzymek 25 +04002013-10-25T23:40:51+04:00312013bEurope/MoscowFri, 25 Oct 2013 23:40:51 +0400 2013, 23:40:51
0

Попробуйте это:

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;

public class TestController {
   private JFrame frame;
   int[] tmp;

   public TestController(JFrame frame) {
      this.frame = frame;
   }

   public void finish() {
      if (dia != null) {
         dia.dispose();
      }
      tmp = null;
   }

   class TDialog extends JDialog {
      public TDialog() {
         super(frame, "Dialog", true);
         this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
      }
   }

   TDialog dia;

   public void run() {
      tmp = new int[40000000];
      for (int i = 0; i < tmp.length; i += 10)
         tmp[i] = new Random().nextInt();
      dia = new TDialog();
      dia.setVisible(true);
   }

   public static void main(String[] args) {
      EventQueue.invokeLater(new Runnable() {
         @Override
         public void run() {
            final JFrame frame = new JFrame("test");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.setLocationRelativeTo(null);
            frame.setSize(200, 200);
            JButton button = new JButton("button");
            button.addActionListener(new ActionListener() {
               @Override
               public void actionPerformed(ActionEvent e) {
                  TestController controller = new TestController(frame);
                  controller.run();
                  // controller = null;
                  System.out.println("here");
                  controller.finish();
               }
            });
            frame.add(button);
            frame.setVisible(true);
         }
      });
   }
}

где вы очищаете диалоговое окно и его данные в методе finish(). Диалог снова должен быть модальным, чтобы это работало, иначе вам понадобится WindowListener.


Вы заявляете в комментарии:

  

Но не могли бы вы сказать мне, что не так в моем коде? и что означает "быть модальным". Я прочитал API метода Dialog setModal в документе Java. это означает, что «когда блоки диалогового окна вводятся в другие окна при их отображении», кажется, не то, что вы упоминали.

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

Не существует волшебного решения вашей проблемы, поскольку диалоговое окно само по себе является модальным, но оно позволяет нам точно знать, когда диалоговое окно больше не отображается - код возобновляется с того места, где диалоговое окно было установлено видимым, и, таким образом, позволяет нам вызовите код очистки на этом этапе. Здесь я вызываю метод finish().

Если вы не хотите, чтобы диалоговое окно было модальным, вам понадобится WindowListener и прослушайте закрываемое диалоговое окно, а затем выполните там свой вызов метода Finish.

Все, что делает мой код, - это проверяет, что массив int доступен для GC'ing, прежде чем создавать новый массив int.

ответил Hovercraft Full Of Eels 25 +04002013-10-25T23:43:13+04:00312013bEurope/MoscowFri, 25 Oct 2013 23:43:13 +0400 2013, 23:43:13

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132