Java排列会导致堆空间错误

时间:2015-08-13 16:56:22

标签: java algorithm exception permutation heap-memory

我有一个程序可以生成数字组合的排列。排列具有给定的大小(在这种情况下为6)。我的问题是我得到一个 java.lang.OutOfMemoryError:Java堆空间错误,其中包含更大的数字组合。例如,如果我计算18个数字中的permations,我会得到这个例外:

Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at javax.swing.text.GapContent.allocateArray(Unknown Source)
at javax.swing.text.GapVector.resize(Unknown Source)
at javax.swing.text.GapVector.shiftEnd(Unknown Source)
at javax.swing.text.GapContent.shiftEnd(Unknown Source)
at javax.swing.text.GapVector.open(Unknown Source)
at javax.swing.text.GapVector.replace(Unknown Source)
at javax.swing.text.GapContent.insertString(Unknown Source)
at javax.swing.text.AbstractDocument.handleInsertString(Unknown Source)
at javax.swing.text.AbstractDocument.insertString(Unknown Source)
at javax.swing.text.PlainDocument.insertString(Unknown Source)
at javax.swing.JTextArea.append(Unknown Source)
at test.permute(test.java:48)
at test.permute(test.java:52)
at test.permute(test.java:52)
at test.permute(test.java:52)
at test.permute(test.java:52)
at test.permute(test.java:52)
at test.permute(test.java:52)
at test.actionPerformed(test.java:74)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)

现在看起来这是由于在JTextArea中打印出排列引起的,因为如果你看一下异常的第一行,你可以在javax.swing.text看到错误。

以下是我使用的代码:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;

public class test extends JFrame implements ActionListener {

    private JPanel panel;
    private JButton ok;
    private JTextArea text;
    private String str;
    private JScrollPane scroll;

    public test() { 
        panel = new JPanel();
        ok = new JButton("OK");
        ok.addActionListener(this);
        str = ("1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, ");
        text = new JTextArea(str, 16, 16);
        text.setEditable(true); 
        scroll = new JScrollPane(text);
        scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);


        panel.add(scroll);
        panel.add(ok);
        add(panel); 

        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
        new test();
    }

    //-----------------------------------------------------------------------------------
    public void permute(java.util.List<Integer> intList, int k, int max) {
          if(k == max) {
            text.append(Arrays.toString(intList.subList(0, max).toArray()).replaceAll( "\\[|\\]", "") + ", \n");
          } else {
            for(int i = k; i < intList.size(); i++){
              java.util.Collections.swap(intList, i, k);
              permute(intList, k+1, max);
              java.util.Collections.swap(intList, k, i);
            }
          }
    }
    //-----------------------------------------------------------------------------------

    @Override
    public void actionPerformed(ActionEvent arg0) {
        String a = text.getText();  
        text.setText("");

        String[] zahlenstring = a.split(", ");
        int[] zahlenint = new int[zahlenstring.length];

        for(int i = 0; i < zahlenstring.length ;i++) {
            zahlenint[i] = Integer.parseInt(zahlenstring[i]); }

        ArrayList<Integer> intList = new ArrayList<Integer>();
        for (int i = 0; i < zahlenint.length; i++) {
            intList.add(zahlenint[i]); }

        permute(intList, 0, 6);    
    }
}

我寻找解决方案,但我主要找到了将ram添加到java或使用多线程的建议,我不想在这里使用。

现在我的问题是:如何改进此代码,以便它不再给我这个代码?这里有什么改进的吗?

如果您仍有疑问,可以在评论中提问。提前谢谢。

2 个答案:

答案 0 :(得分:0)

不是建立一个使用非常大(或不切实际)的内存量的String,而是需要在确定时处理每个排列。

myqlabel.setAutoFillBackground(True)

此解决方案不会再使用任何内存。

要随时显示此结果,您可以

public static void permute(List<Integer> intList,  Consumer<List<Integer>> permutationConsumer) {
    permute(intList, 0, intList.size(), permutationConsumer);
}

public static void permute(List<Integer> intList, int k, int max, Consumer<List<Integer>> permutationConsumer) {
   if(k == max) {
        permutationConsumer.accept(intList.subList(0, max));
        return;
   }
   for(int i = k; i < intList.size(); i++) {
        Collections.swap(intList, i, k);
        permute(intList, k + 1, max, permutationConsumer);
        Collections.swap(intList, k, i);
   }
}

在显示之前,这不会构建一个大字符串,因此您不会耗尽内存。

答案 1 :(得分:0)

当您处理大量元素时,最好事先计算它们将消耗多少内存。

您的排列将消耗permutations[1]个字节,假设每个组合消耗12个字节。所以消耗的内存总量大约为160MB。仅需将此内存量存储为字符串。当您将它们添加到TextArea时,您至少将所需内存量增加一倍。

解决内存问题的最简单方法是在计算后立即输出排列。您可以将其写入控制台或文件。在这种情况下,您不需要任何额外的内存。

但是,如果您唯一的选择是创建GUI应用程序,那么您可以执行以下操作。首先,你需要意识到你需要至少(13366080 * k)字节来换列字符串(其中k是每个排列的大小为字符串),13366080 * 16字节用于存储字符串数组和一些额外的内存使应用程序顺利运行(防止GC暂停)。如果我的计算是正确的,它将是大约500Mb的堆内存。

接下来,您不应将字符串直接添加到TextArea。相反,创建排列的ArrayList<String>,创建ScrollBar,使用结果数组的大小初始化它。在ScrollBar的位置更改时,使用ScrollBar位置处的元素重新初始化TextArea(从滚动条的位置获取一些少量元素,并将它们作为行添加到TextArea中)。