繁体   English   中英

java垃圾收集在对话框中

[英]java garbage collecting in dialog

*当我尝试在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); } }); } } 

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

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

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

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

您之前正在分配new int[40000000] ,而tmp仍保留对最后一个int[40000000]的引用。
tmp = new int[40000]这样的表达式中的操作顺序是:

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

所以在1. tmp仍然保持对它的最后一个值的引用。

尝试做:

tmp = null;
tmp = new int[40000000];

尝试这个:

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。


你在评论中说:

但是你能告诉我我的代码有什么问题吗? 什么是“模态”的含义。 我在java doc中读过Dialog的setModal方法的api。 它意味着“对话框是否在显示时阻止输入到其他窗口”,看起来与你提到的不一样。

模式对话框实际上是一个阻止来自调用窗口的输入的对话框,实际上只要对话框可见,就会从调用代码中冻结代码流。 一旦对话框不再可见,代码就会恢复。

对话框本身就是模态的,你的问题没有神奇的解决方案,但是它可以让我们确切地知道对话框何时不再可见 - 代码从对话框设置可见的地方恢复,从而允许我们调用clean-此时代码。 在这里我调用finish()方法。

如果您不希望对话框是模态的,那么您需要一个WindowListener并监听关闭的对话框,然后在那里进行完成方法调用。

我的所有代码都是在创建新的int数组之前确保int数组可用于GC。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM