在对话框中收集java垃圾 [英] java garbage collecting in dialog

查看:92
本文介绍了在对话框中收集java垃圾的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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


  1. 如果我不创建对话框并显示它,则不会出现内存问题。

  2. 如果我添加了一个调用System.gc()到对话框的windowsCloseListener,没有内存问题。
  3. 如果我在运行时调用System.gc ()方法,显示内存问题。

      public class TestController {
    int [] tmp;

    class TDialog扩展了JDialog {
    public TDialog(){
    super();
    this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    //如果我取消这段代码,OutOfMemoryError似乎在这种情况下消失
    //但我确定它不是一个可接受的解决方案
    / *
    this.addWindowListener(new WindowAdapter(){
    public void windowClosing(WindowEvent e){
    System.out.println(windowsclose);
    TDialog.this.dispose();
    System.gc ();
    }
    });
    * /
    }
    }

    TDialog dia;
    $ b $ public void run(){
    //如果我在这里执行System.gc(),OutOfMemoryError仍然存在
    // System.gc();
    tmp = new int [40000000];
    for(int i = 0; i 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);
    }
    });


    code $


    我已经阅读了很多描述java的GC工作原理的文章。我认为如果java试图在堆中分配一些空间并且它没有足够的可用空间,那么java将会执行gc,并且如果一个对象不能通过GC graph从GC根访问,其中一个边u到v表示你有一个对v的引用,root是一个线程工作栈或本地资源中的东西,它没有用,并且可以被java的GC收集。



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

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

    解决方案

    您之前正在分配新的int [40000000] ,而 tmp 仍然保留对最后一个 int [40000000]

    表达式中的操作顺序如 tmp = new int [40000] 是:


    1. new int [40000]

    2. 将对数组的引用赋给 tmp

    1 tmp 仍然保留对其最后一个值的引用。尝试做:

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


    *I'm now encountering a very strange java GC problem when I trying to make a button in a JFrame, and when I click the button, it display a JDialog which need to deal with and show some images and need nearly 200M memory. But the problem is when I close the dialog and reopen it, sometimes it cause java.lang.OutOfMemoryError. (not every times)

    Trying to solve the problem, I simplify this problem and make some experiment, which cause me more confused.

    The Code I used in my " experiment " is showed below. When I click a button in a frame, I allocate 160M memory for an integer array, and display a dialog, But If I close the dialog and reopen it, OutOfMemoryError appears. I adjusting the code and the result is:

    1. If I don’t create the dialog and show it, no memory problem.
    2. If I add a windowsCloseListener which invoke System.gc() to the dialog, no memory problem.
    3. If I invoke System.gc() in the run() method, memory problem shows.

      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);
            }
          });
        }
      }
      

    I’ve read about a lot articles which describe how java’s GC work. I think if java trying to allocate some space in the heap and it do not have enough free space, java will do gc, and if a object can’t be accessed from the gc root through "GC graph", in which a edge from u to v represent u have a reference to v, root is something in the a thread working stack, or native resources, It’s useless and qualified to be collected by java’s GC.

    Now the problem is When I click the button and trying to create an Integer array, the Integer array I create last time is certainly qualified to be collected by java’s GC. So why it caused Error.

    Apologize for Such A Long Description…I don’t have much tactics in asking problem, so just trying to make it clear.

    Besides, The parameter I used to start jvm is " java –Xmx256m"

    解决方案

    You're allocating new int[40000000] before while tmp still holds the reference to the last int[40000000].
    The order of operation in an expression like tmp = new int[40000] is:

    1. new int[40000]
    2. Assign the reference to the array to tmp

    So in 1. tmp is still holding the reference to it's last value.

    Try doing:

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

    这篇关于在对话框中收集java垃圾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆