Почему рекурсивная программа со временем тормозит?

У пеня есть программа:

private void main(PositionList Ps) {
        if (xx >= 1900) setTextR(xx+" ");//Чтобы увидеть где программа тормозит
        xx++;
        PositionList Ps1 = new PositionList();
          Ps1.setSize(Ps.size()+1);
        this.copyPositionList(Ps,Ps1);// Если эту строку убрать, то программа работает нормально
        this.main(Ps1);

private void copyPositionList(PositionList V, PositionList Vc) {
        Position v;
        int i = 0; 
        Position p = null;
        
        while (i < V.size()){
          v = V.list[i];
          p = new Position();
         
          if (v.questions != null) {// p.questions = copyTerms(v.questions);
        
            Node t = v.questions.first;
            NodeList TC = new NodeList();  
            while (t != null){
              // TC.addLast(copyTerm(t)); -->
              Node tc1 = new Node();
              tc1.term = new Term(); 
              tc1.term.name = t.term.name;
              TC.addLast(tc1);
          
               t = t.next;
             }
             p.questions = TC;
        
          }
          //  p.vars = copyVars(v.vars); -->
        p.vars = new LinkedList<Var>();
      
        Iterator<Var> Vi = v.vars.iterator();
        Var vv;
        if(Vi.hasNext()){vv=Vi.next();}else{vv=null;}
        
        while (vv != null){
          Var vc = new Var();
          vc.name = vv.name;
          
          if (vv.term != null) {// На всякий случай
            vc.term = new Term();
            vc.term.name = vv.term.name;
          }
          p.vars.add(vc);
        
          if(Vi.hasNext()){vv=Vi.next();}else{vv=null;}
        }
        
          p.n[0] = v.n[0];
          Vc.list[i] = p;
          
          i++;
        }
        
        Vc.list[i] = p;
      }

Главная рекурсивная процедура main() запускается в фоновом потоке. Где-то на 2700 рекурсии main() прокрамма местами останавливается на 2 секунды, потом это происходит все чаще, пока через 100 рекурсий программа уже совсем топчится на месте.
Внимание: это программа сокращенная версия моего приложения.
Если убрать из main() copyPositionList, то все нормально.
В чем дело?

Пробовал переводить все рекурсии в циклы и наоборот - все циклы в рекурсии. Результат один и тот же - при том же количестве основного цикла, что и числа рекурсий основной процедуры программа застапаривается.

Я перевел все рекурсии в циклы. Добавил в главный цикл:

         if (xx==2600) {
            Pos.clear();
            Pos.add(Ps);
          }

Тоесть, наш двумерный массив (своеобразный стэк для отката вычислений) очищается и в него снова добавляется один элемент одномерного массива с одним элементом.
Этот двумерный массив растет в цикле так:

1 1 1 1 1 … 1
2 2 2 2 2
3 3 3 3
4 4. 4
5. 5
6
7
N
После такого перезапуска массива, программа перестает на 2700 цикле зависать, как-будто занаво перезапустилась. Но у меня ведь максимальный объем массива половина от матрицы 2600х2600. Эти не такие и большие данные.
Что мне делать в этой ситуации?

Если дело не в алгоритме, то может сборщик мусора срабатывает в этот момент, хотя 2 сек вроде много.
Но наверно просто либо copyPositionList становится медленным с ростом размера списков, либо то, что вы со списками делаете потом.

Профайлеры могут помочь понять в чем дело в подобных случаях
A Guide to Java Profilers | Baeldung


Для вставки кода на форумах нужно использовать кнопку Код, а не Жирный )

Я добавил в основной цикл:
Runtime.getRuntime().freeMemory()
для вывода на экран. И узнал.
Программа работает за раз не со всей свободной оперативной памятью, а берет по 25 мб. Когда заканчивается выделенная память - берет еще 25 мб (программа при этом виснет сек. на 2-3) и т.д.
Проблема в том, что мой двумерный массив (стэк) со временем занимает не один и не два таких размерчика из-за чего программа виснет на минуты.
Не могу найти в интернете: как задать программе, чтобы она хватала не по 25мб, а например по 100мб?

Я бы использовал malloc()

Так может не из-за памяти виснет. Добавьте вывод в каждой функции и т.п., чтобы узнать когда какая выполняется и сколько. Может вы там что-то сложное по времени делаете в основой части программы с этими списками.

Уже делал так. Стоило мне, например, для какой-нибудь переменной типа LinkedList убрать add(…), как программа висла в других местах.

Добавив Runtime.getRuntime().freeMemory() для вывода на экран показало, что когда заканчивается свободная память, программа привисает сикунды на 2-3. А потом выводится на экран, что свободной памяти снова 25мб. В скором времени это происходит все чаще, пока программа не зависает на долго.

Это вы о чем? Обьясните, пожалуйста, развернутее, я с этим не работал.

Так и что было когда делали? Где зависало?

Из этого вряд ли можно сделать вывод, что дело в памяти. Меньше данных для обработки, вот и тратит меньше времени.

Программа повторяла одни и те же действия, раз за разом.

...
   if (v == V.getLast()&& w.equals("@")) setTextR("#0");
          Vc.addLast(p);
             if (v == V.getLast()&& w.equals("#0")) setTextR("#1");
          if(Vi.hasNext()){v=Vi.next();}else{v=null;}
             if (v == V.getLast()&& w.equals("#1")) setTextR("#2");
....

Она висла между setTextR("#0") и setTextR("#1"). А если убирал что-то из кода программы, то - между setTextR("#1") и setTextR("#2").

Так тут непонятно что когда выполняется из-за условий. Я бы просто в начало функций или каких-то важных блоков воткнул без всяких условий. Или профайлер.

1 лайк

Я еще упростил программу для нахождения возникшей проблемы:

LinkedList<PositionList> Pos = new LinkedList<PositionList>();
        Pos.add(Ps);//Вставляем 1-ый одноэлементный список
        
        while (xx <= 4000) {//Создаем матрицу со списками, пока без данных
          if (xx >= 3400) {
            setTextR(xx+"-"+Runtime.getRuntime().freeMemory()+" ");
          }
          
          int size0 = Pos.getLast().size();
          Pos.add(new PositionList());
          Pos.getLast().setSize(size0+1);
          
          int i = 0; 
          Position p;
          
          while (i < size0){
            p = new Position();
            p.questions = new NodeList();
            p.vars = new LinkedList<Var>();
            Pos.getLast().list[i] = p;
            i++;
          }
          p = new Position();
          p.questions = new NodeList();
          p.vars = new LinkedList<Var>();
          Pos.getLast().list[i] = p;
        
          xx++;
        }

На 3406 итерации цикла, программа виснет, а минут через две ее “выбрасывает”. Озу у меня хватает - 1гб свободной памяти. И не понятно почему так много памяти ест?

с какой ошибкой?

Не показывает ошибку, ничего не показывает почему-то.

А какая библиотека подключается для работы с malloc()?

ХЗ как в Java распределять память, гугл подсказал пару примеров:
Native Memory Allocation in Java

Я нашел, что у меня во многих местах после использования переменной объектного типа, не присваивается переменной null. Исправив это упущении, моя программа стала работать дольше, но по-прежнему не хватает памяти. Я узнал, что на моем смартфоне максимальное значение выделямой памяти для приложения - 512 мб, а для моего приложения этого оказалось мало. Пробовал с рут правами увеличить размер выделяемой памяти, но на моем телефоне рут прав нет! Теперь подумываю о приобретении хорошего смартфона.