Прежде всего, вам нужно убедиться, что вы понимаете, что вызывает OutOfMemoryError (OOME). Вы делаете пару ссылок на распространение вычислений с течением времени. Я могу неправильно понять, что вы подразумеваете под этим, но, как сказано, это не будет иметь никакого значения в этой ситуации.
OOMEs являются результатом 1. JVM, не имеющего свободного смежного блока пространства, достаточно большого для хранения нового объекта после, освобождая весь мусор и уплотняя кучу. Время в действительности не является фактором. Если память достижима, ее невозможно собрать независимо от того, как долго она была вокруг.
Таким образом, существует несколько причин, по которым у вас может возникнуть проблема. Во-первых, вы пытаетесь создать очень большой объект (какие строки позволяют вам делать), и нет свободного блока кучи, достаточно большого для его размещения. Другая причина заключается в том, что вы заполнили кучу объектами, которые не собираются, потому что вы все еще ссылаетесь на них.
В этом случае, я думаю, проблема заключается в том, что вы помещаете все строки в arraylist, чтобы они не могли быть собраны до окончания выполнения метода. Стоит отметить, что substr фактически создает новую строку, которая ссылается на массив символов исходной строки и, следовательно, не позволит ее собирать. Это может быть проблемой, если вы хотите вытащить небольшой бит текста из большой строки и отказаться от остальных. Я не думаю, что это проблема, но хорошо знать все то же самое.
Самый эффективный способ уменьшить память - создать собственный класс Collection и сгенерировать каждую перестановку при вызове итератора. Это исключило бы необходимость сохранения всех перестановок в памяти одновременно. Если я получу минуту, я отправлю код примера.
Редактировать: Я разработал пример без изменения фундаментальной структуры вашего алгоритма. Он должен работать в обычном JVM для больших входов, чем вы когда-либо захотите подождать до конца. По существу, помещая все результаты в Arraylist, ваше потребление памяти растет факториальной скоростью по отношению к вашей длине строки ввода. Исключая хранение результатов, нижеприведенный подход использует использование памяти, которое растет линейно по отношению к длине входной строки.
Это не идеально, и есть некоторые проблемы, которые я оставляю читателю для решения. Подсказка: что произойдет, если вы создадите Permutor с пустой строкой?
Как кто-то упомянул StringBuffer не самый лучший выбор здесь, но вы, вероятно, даже лучше, используя подстроку и Concat что-то вроде этого:
current.substring(0, position).concat(last).concat(current.substring(position));
Пример:
public class Example
{
public static void main(String... args) {
Permutor p = new Permutor("abcdefghijklmnopqrstuvwxyz");
System.out.println(p.size());
int i = 0;
for (String s : p) {
System.out.println(i++ + ": " + s);
}
}
public static int factorial(int n) {
int fact = 1;
for (int i = 1; i <= n; i++) {
fact *= i;
}
return fact;
}
public static class Permutor extends AbstractCollection<String>
{
private String characters;
public Permutor(String s)
{
characters = s;
}
@Override
public Iterator<String> iterator()
{
if (characters.length() == 1) {
return Collections.singleton(characters).iterator();
} else {
return new PermutingIterator(characters);
}
}
@Override
public int size()
{
return factorial(characters.length());
}
}
private static class PermutingIterator implements Iterator<String>
{
private final char last;
private final Iterator<String> inner;
private String current;
private int position;
PermutingIterator(String s)
{
int lastIndex = s.length() - 1;
this.inner = new Permutor(s.substring(0, lastIndex)).iterator();
this.last = s.charAt(lastIndex);
}
@Override
public boolean hasNext()
{
return inner.hasNext() || (current != null && position <= current.length());
}
@Override
public String next()
{
while(true) {
if (current != null && position <= current.length()) {
return new StringBuffer(current).insert(position++, last).toString();
} else if (inner.hasNext()) {
position = 0;
current = inner.next();
} else {
throw new IllegalStateException("no more permutations available");
}
}
}
@Override
public void remove()
{
throw new UnsupportedOperationException();
}
}
}
Можете ли вы показать нам, как выглядит ваш алгоритм, чтобы мы знали, как его распространять? –
Я отредактировал код. –
Факториалы растут * действительно * быстро. Но это не похоже, что вы вызываете этот метод в любом месте. Должны ли вы быть? –