java垃圾收集在对话框中

rya*_*aaa 7 java swing garbage-collection memory-leaks

*当我尝试在JFrame中创建一个按钮时,我现在遇到一个非常奇怪的java GC问题,当我单击该按钮时,它会显示一个需要处理并显示一些图像并需要近200M内存的JDialog.但问题是当我关闭对话框并重新打开它时,有时它会导致java.lang.OutOfMemoryError.(不是每次都)

试图解决这个问题,我简化了这个问题并做了一些实验,这让我更加困惑.

我在"实验"中使用的代码如下所示.当我单击框架中的按钮时,我为整数数组分配160M内存,并显示一个对话框但是如果我关闭对话框并重新打开它,则会出现OutOfMemoryError.我调整代码,结果是:

  1. 如果我不创建对话框并显示它,没有内存问题.
  2. 如果我添加一个调用System.gc()的windowsCloseListener到对话框,没有内存问题.
  3. 如果我在run()方法中调用System.gc(),则显示内存问题.

    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);
          }
        });
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)

我读过很多描述java的GC工作方式的文章.我认为如果java试图在堆中分配一些空间并且没有足够的可用空间,java将执行gc,并且如果无法通过"GC graph"从gc根访问对象,其中的边缘来自u表示你有一个对v的引用,root是一个线程工作堆栈中的东西,或者是本机资源,它是无用的,有资格被java的GC收集.

现在问题是当我单击按钮并尝试创建一个Integer数组时,我上次创建的Integer数组肯定有资格被java的GC收集.那么为什么它会导致错误.

为这样一个长篇描述道歉...我在提出问题时没有太多的策略,所以只是试图说清楚.

此外,我用来启动jvm的参数是"java -Xmx256m"

rzy*_*mek 3

您在之前进行分配new int[40000000],同时tmp仍然保留对最后一个的引用 int[40000000]
表达式中的运算顺序如下tmp = new int[40000]

  1. new int[40000]
  2. 将数组的引用分配给tmp

所以在1. tmp中仍然保留对其最后一个值的引用。

尝试做:

tmp = null;
tmp = new int[40000000];
Run Code Online (Sandbox Code Playgroud)