我有一个程序可以生成数字组合的排列。排列具有给定的大小(在这种情况下为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或使用多线程的建议,我不想在这里使用。
现在我的问题是:如何改进此代码,以便它不再给我这个代码?这里有什么改进的吗?
如果您仍有疑问,可以在评论中提问。提前谢谢。
答案 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)
当您处理大量元素时,最好事先计算它们将消耗多少内存。
您的排列将消耗个字节,假设每个组合消耗12个字节。所以消耗的内存总量大约为160MB。仅需将此内存量存储为字符串。当您将它们添加到TextArea时,您至少将所需内存量增加一倍。
解决内存问题的最简单方法是在计算后立即输出排列。您可以将其写入控制台或文件。在这种情况下,您不需要任何额外的内存。
但是,如果您唯一的选择是创建GUI应用程序,那么您可以执行以下操作。首先,你需要意识到你需要至少(13366080 * k)字节来换列字符串(其中k是每个排列的大小为字符串),13366080 * 16字节用于存储字符串数组和一些额外的内存使应用程序顺利运行(防止GC暂停)。如果我的计算是正确的,它将是大约500Mb的堆内存。
接下来,您不应将字符串直接添加到TextArea。相反,创建排列的ArrayList<String>
,创建ScrollBar,使用结果数组的大小初始化它。在ScrollBar的位置更改时,使用ScrollBar位置处的元素重新初始化TextArea(从滚动条的位置获取一些少量元素,并将它们作为行添加到TextArea中)。