Stackoverflow как исправить

Это означает, что в стеке недостаточно места.

Причины — например, слишком глубокая рекурсия (редко), или слишком большие локальные переменные (куда чаще), или и то и другое сразу :)

Как избавиться? Опять же, можно просто в настройках компилятора поднять размер стека.

Но надежнее и лучше — посмотреть, нет ли слишком глубокой (вплоть до бесконечности) рекурсии, заменить локальные массивы на выделяемые динамически.

int f()
{
    int a[1000000];

практически гарантированно даст переполнение стека. В отличие от

int f()
{ 
    int * a = new int[1000000];  // Только не забудьте потом удалить...

или

    vector<int> a(1000000);

Словом, смотрите, кто съедает много стековой памяти, и избавляйтесь от него…

В мире программистов ошибка «stack overflow» очень известна благодаря тому, что этот вид ошибки довольно распространен. А сам термин «stack overflow» известен еще больше, чем ошибка, благодаря одноименному англоязычному ресурсу «StackOverflow». Это сообщество программистов международного масштаба, и еще куча всего интересного. Поэтому не нужно путать ошибку «stack overflow» и веб-ресурс с таким же названием. В нашей статье речь пойдет об ошибке.

Ошибка «stack overflow» связана с переполнением стека. Она появляется в том случае, когда в стеке должно сохраниться больше информации, чем он может уместить. Объем памяти стека задает программист при запуске программы. Если в процессе выполнения программы стек переполняется, тогда возникает ошибка «stack overflow» и программа аварийно завершает работу. Причин возникновения подобной ошибки может быть несколько.

Ошибка «stack overflow»

Нужно отметить, что ошибка «stack overflow» не связана с конкретным языком программирования, то есть она может возникнуть в программах на Java, C++, C, C# и других компилируемых языках.

Причин ее возникновения может быть несколько. К самым распространенным причинам относятся:

  • бесконечная рекурсия;

  • глубокая рекурсия;

  • проблемы с переменными в стеке.

Бесконечная рекурсия и ошибка «stack overflow» 

Бесконечная рекурсия редко возникает самостоятельно и по неизвестным причинам. Обычно программист:

  • забывает прописывать условие для выхода из рекурсии;

  • пишет неосознанную косвенную рекурсию.

Самая частая причина из категории «бесконечной рекурсии» программист забывает прописывать условия выхода или же прописывает, но условия выхода не срабатывают.

Вот как это выглядит на С:

int factorial (int number)

{

  if (number == 0)

    return 1;

  return number * factorial(number — 1);

}

В описанном примере прописаны условия выхода из рекурсии, однако они никогда не сработают, если «number» будет отрицательным. Поэтому через несколько миллионов вызовов стек будет переполнен и возникнет ошибка «stack overflow». В некоторых языках программирования предусмотрена «защита» от таких рекурсий. В них рекурсия из конца функции конвертируется в цикл, что не будет расходовать стековую память. Но подобная «оптимизация» вызовет другую, менее опасную проблему «зацикливание».

Неосознанная бесконечная рекурсия возникает в том случае, если программист по невнимательности распределяет один и тот же функционал программы между разными нагруженными функциями, а потом делает так, что они друг друга вызывают.

В коде это выглядит так:

 int Object::getNumber(int index, bool& isChangeable)

{

  isChangeable = true;

  return getNumber(index);

}

int Object::getNumber(int index)

{

  bool noValue;

  return getNumber(index, noValue);

}

Глубокая рекурсия и ошибка «stack overflow»

Глубокая рекурсия — это такая рекурсия, которая имеет свое окончание через определенное время, поэтому она не бесконечная. Однако памяти стека не хватит для завершения такой рекурсии, поэтому ошибка «stack overflow» обеспечена. Обычно такая ситуация заранее просчитывается программистом,поэтому ее можно решить. Например, можно:

  • отыскать другой программный алгоритм для решения поставленной задачи, чтобы избежать применения рекурсии;

  • «вынести» рекурсию за пределы аппаратного стека в динамический;

  • и другое.

Глубокая рекурсия выглядит так:

void eliminateList(struct Item* that)

{

    if (that == NULL)

        return;

    eliminateList(that->next);

    free(that);

}

Проблемы с переменными в стеке и ошибка «stack overflow»

Если взглянуть на популярность возникновения «stack overflow error», то причина с проблемными переменными в стеке стоит на первом месте. Кроется она в том, что программист изначально выделяет слишком много памяти локальной переменной.

Например:

int function() {

     double b[1000000]

}

В данном случае может возникнуть такая ситуация, что массиву потребуется объем памяти, который стек не способен будет обеспечить, а значит, возникнет ошибка «stack overflow». 

Заключение

Ошибка «stack overflow» возникает довольно часто. Каждый конкретный случай ее возникновения требует собственного решения. Одна причина объединяет возникновение такой ошибки — невнимательность программиста. Если «stack overflow error» возникла, значит, программист где-то что-то упустил или не доглядел.

StackOverFlowError is one of the common confronted JVM errors. In this blog post, we will look at the inner mechanics of thread stacks, reasons that can trigger StackOverFlowError, and potential solutions to address this error.

To gain deeper understanding into StackOverFlowError, let’s review this simple program:

public class SimpleExample {

      public static void main(String args[]) {

            a()
      }

      public static void a() {

            int x = 0;
            b();
      }

      public static void b() {

            Car y = new Car();
            c();
      }

      public static void c() {

            float z = 0f;
      System.out.println("Hello");
      }
}

This program is very simple with the following execution code:

  1.  main() method is invoked first
  2.  main() method invokes a()  method. Inside a() method, the integer variable ‘x’ is initialized to value 0.
  3.  a() method in turn invokes b() method. Inside b() method, the Car object is constructed and assigned to variable ‘y.’
  4.  b() method in turn invokes the c() method. Inside the c() method, the float variable ‘z’ is initialized to value 0.

Now, let’s review what happens behind the scenes when above simple program is executed. Each thread in the application has its own stack. Each stack has multiple stack frames. The thread adds the methods it’s executing, primitive data types, object pointers, and return values to its stack frame in the sequence order in which they are executed.

thread-stack-frame-1

Fig 1: Thread’s Stack frame

Step #1: main() method is pushed into the application thread’s stack.

Step #2: a() method is pushed into application thread’s stack. In a() method, primitive data type ‘int’ is defined with value 0 and assigned to variable x. This information is also pushed into the same stack frame. Note that both data, i.e. ‘0’ and variable ‘x,’ is pushed into thread’s stack frame.

Step #3: b() method is pushed into thread’s stack. In the b() method, the Car object is created and assigned to variable ‘y.’ A crucial point to note here is that the ‘Car’ object is created in the heap and not in the thread’s stack. Only the Car object’s reference, i.e. y, is stored in the thread’s stack frame.

Step #4: c() method is pushed into thread’s stack. In c() method, primitive data type ‘float’ is defined with value 0f and assigned to variable z. This information is also pushed into same stack frame. Note both data, i.e. ‘0f’ and variable ‘z,’ is pushed into thread’s stack frame.

Once each method’s execution is completed, then the method and the variables/object pointers are stored in the stack frame are removed, as shown in Fig 2.

thread-stack-frame-2

Fig 2: Thread’s stack frame after executing methods

What Causes StackOverflowError?

As you can see, thread’s stack is storing methods it’s executing, primitive datatypes, variables, object pointers, and return values. All of these consume memory. If thread’s stack sizes grow beyond the allocated memory limit, then StackOverflowError is thrown. Let’s look at the below buggy program, which will result in a  StackOverflowError:

public class SOFDemo {

         public static void a() {

                  // Buggy line. It will cause method a() to be called infinite number of times.
                  a();
         }

         public static void main(String args[]) {

                   a();
         }
}

In this program, the main() method invokes a()  method. a() method recursively calls itself. This implementation will cause  a() method to be invoked infinite number of times. In this circumstance, a() method will be added to thread’s stack frame infinite number of times. Thus, after a few thousand iterations, thread’s stack size limit would be exceeded. Once stack size limit is exceeded, it will result in  StackOverflowError:

Exception in thread "main" java.lang.StackOverflowError
       at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
       at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
       at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
       at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
       at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
       at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
       at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)
       at com.buggyapp.stackoverflow.SOFDemo.a(SOFDemo.java:7)

stackOverflowError

Fig 3: StackOverflowError progression

What Are the Solutions to StackOverflowError?

There are couple of strategies to address  StackOverflowError.

1. Fix the Code

Because of a non-terminating recursive call (as shown in the above example), threads stack size can grow to a large size. In those circumstances, you must fix the source code that is causing recursive looping. When ‘StackOverflowError’ is thrown, it will print the stacktrace of the code that it was recursively executing. This code is a good pointer to start debugging and fixing the issue. In the above example, it’s the a()  method.

2. Increase Thread Stack Size (-Xss)

There might be legitimate reason where a threads stack size needs to be increased. Maybe thread has to execute large number of methods or lot of local variables/created in the methods thread has been executing? In such circumstances, you can increase the thread’s stack size using the JVM argument: ‘-Xss.» This argument needs to be passed when you start the application. Example:

-Xss2m

This will set the thread’s stack size to 2 mb.

It might bring a question: what is the default thread’s stack size? Default thread stack size varies based on your operating system, Java version, and vendor.

JVM version

Thread stack size

Sparc 32-bit JVM

512k

Sparc 64-bit JVM

1024k

x86 Solaris/Linux 32-bit JVM

320K

x86 Solaris/Linux 64-bit JVM

1024K

Windows 32-bit JVM

320K

Windows 64-bit JVM

1024K

Data Types
Frame (networking)
Java (programming language)
Java virtual machine
32-bit
64-bit
Primitive data type

Opinions expressed by DZone contributors are their own.

SEVI

31 / 30 / 2

Регистрация: 26.01.2010

Сообщений: 124

Записей в блоге: 1

1

27.01.2014, 00:17. Показов 4579. Ответов 40

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Доброго времени суток!
Дело в том, что при объявлении массива размером 106

C++
1
int a[1000000];

выскакивает при запуске (после компиляции даже) stack overflow, еще до того как туда будут заноситься элементы. Дебаггер указывает именно сюда… Тем более если сделать 105, то все работает… Прошу объяснить как это обойти… Заранее спасибо.
Вот весь код (без кода функции двоичной сортировки quickSortR)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{
    int n, k, i, s=0;
    int a[100000];
    ifstream f1("E.dat");
    ofstream f2("E.sol");
    f1 >> n >> k;
    for (i = 0; i < n; i++) {
        f1 >> a[i];
    }
    quickSortR(a,n-1);
    for (i = k; i < n; i++) {
        s = s + a[i];
    }
    f2 << s;
}



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

27.01.2014, 00:17

Ответы с готовыми решениями:

Ошибка «stack overflow». Разложение функции в ряд Тейлора
Задание: рекурентно реализовать разложение ф-ии {sin}^{2} по ряду Тэйлора. Выдает ошибку…

Быстрая сортировка: ошибка «Stack overflow»
Не понмаю, пишет STACK OVERFLOUDED!!!!
не знаю в чем проблема.
#include &lt;iostream&gt;
#include…

Ошибка: «Unhandled exception: Stack cookie instrumentation code detected a stack-based buffer overrun»
Не могу понять почему значение ChoiceOfPlayer меняется и почему NumberOfRow и NumberOfColumn всегда…

В зависимости от времени года «весна», «лето», «осень», «зима» определить погоду «тепло», «жарко», «холодно», «очень холодно»
В зависимости от времени года &quot;весна&quot;, &quot;лето&quot;, &quot;осень&quot;, &quot;зима&quot; определить погоду &quot;тепло&quot;,…

40

320 / 225 / 74

Регистрация: 22.11.2013

Сообщений: 865

Записей в блоге: 1

27.01.2014, 00:26

2

А в настройках компилятора ничего не меняли? Нормально принял VC++2012 ваш код. Я сам создавал массивы большей длины, тема до боли знакома. Но вы вроде к пределам возможностей 32 разрядной системы и близко не подошли.



0



31 / 30 / 2

Регистрация: 26.01.2010

Сообщений: 124

Записей в блоге: 1

27.01.2014, 00:35

 [ТС]

3

mustimur, а вы в коде меняли на 1000000? А то я оставил случайно 100000… У меня VC++2013. Настроек не менял…



0



238 / 49 / 6

Регистрация: 10.06.2012

Сообщений: 268

Записей в блоге: 1

27.01.2014, 00:36

4

Проверьте, возможно где-то в файле есть число, большее чем 231-1 (2 147 483 647). Либо n>106.



0



31 / 30 / 2

Регистрация: 26.01.2010

Сообщений: 124

Записей в блоге: 1

27.01.2014, 00:38

 [ТС]

5

Craw, да вот в том то и дело что чисел 6. И они все не привышают 100. И проблема начинается еще до заполнения. И как я говорил проблема пропадает, когда я меняю с 106 на 105



0



mustimur

320 / 225 / 74

Регистрация: 22.11.2013

Сообщений: 865

Записей в блоге: 1

27.01.2014, 00:45

6

Цитата
Сообщение от SEVI
Посмотреть сообщение

mustimur, а вы в коде меняли на 1000000? А то я оставил случайно 100000… У меня VC++2013. Настроек не менял…

Да тоже начал вылетать, но если записать так то работает:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
 
int main()
{
    int n, k, i, s=0;
    int *a=new int[1000000];
    ifstream f1("E.dat");
    ofstream f2("E.sol");
    f1 >> n >> k;
    for (i = 0; i < n; i++) {
        f1 >> a[i];
    }
    //quickSortR(a,n-1);
    for (i = k; i < n; i++) {
        s = s + a[i];
    }
     f2 << s;
     delete [] a;
     return 0;
}

Добавлено через 4 минуты
16 строчку раскоментировать забыл



0



31 / 30 / 2

Регистрация: 26.01.2010

Сообщений: 124

Записей в блоге: 1

27.01.2014, 00:47

 [ТС]

7

mustimur, хм… интересно… а почему же тогда не работает тот вид записи… Спасибо! Учту…
Может я ошибаюсь, но этот вид записи используется при динамическом программировании… И получается память выделяется по мере заполнения?



0



320 / 225 / 74

Регистрация: 22.11.2013

Сообщений: 865

Записей в блоге: 1

27.01.2014, 00:54

8

Цитата
Сообщение от SEVI
Посмотреть сообщение

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

Да это динамический массив, но память по него выделяется полностью и сразу в момент определения, в данном случае когда программа доходит до 9 строчки, а освобождается на 21 строчке.



0



SEVI

31 / 30 / 2

Регистрация: 26.01.2010

Сообщений: 124

Записей в блоге: 1

27.01.2014, 01:10

 [ТС]

9

mustimur, кстати говоря у меня работает только без

C++
1
delete [] a;



0



320 / 225 / 74

Регистрация: 22.11.2013

Сообщений: 865

Записей в блоге: 1

27.01.2014, 01:15

10

А с ней ошибку выдает? Это строчка освобождения памяти выделенного под массив. В данном случае не обязательна так память освободится после выполнения программы, но если ты допустим организуешь цикл объявление, то это чревато утечками памяти



0



:)

Эксперт С++

4773 / 3267 / 497

Регистрация: 19.02.2013

Сообщений: 9,046

27.01.2014, 08:30

11



1



320 / 225 / 74

Регистрация: 22.11.2013

Сообщений: 865

Записей в блоге: 1

27.01.2014, 10:35

12

Цитата
Сообщение от Tulosba
Посмотреть сообщение

Должно быть полезно Почему прога может зависать при инициализации массива

А думаете целесообразно менять размер стека? Я не рискнул бы давать такой совет, лучше память выделять динамически на кучи.



0



320 / 225 / 74

Регистрация: 22.11.2013

Сообщений: 865

Записей в блоге: 1

27.01.2014, 10:46

14

Цитата
Сообщение от Tulosba
Посмотреть сообщение

Я и не рекомендую менять этот размер.

Извините не внимательно прочел , просто общая мысль той темы изменение размера стека. Вы то как раз даете рекомендацию аналогично моей



0



:)

Эксперт С++

4773 / 3267 / 497

Регистрация: 19.02.2013

Сообщений: 9,046

27.01.2014, 10:49

15

mustimur, решений проблемы может быть несколько. Самое простое — изменить размер стека, но при этом оно не самое правильное.



0



Эксперт С++

4982 / 3089 / 456

Регистрация: 10.11.2010

Сообщений: 11,165

Записей в блоге: 10

27.01.2014, 11:27

16

SEVI, что тебе мешает выделить память под массив динамически?
Очевидно же что не хватает стековой памяти.



0



320 / 225 / 74

Регистрация: 22.11.2013

Сообщений: 865

Записей в блоге: 1

27.01.2014, 11:27

17

Цитата
Сообщение от Tulosba
Посмотреть сообщение

mustimur, решений проблемы может быть несколько.

Я это прекрасно понимаю.

Цитата
Сообщение от Tulosba
Посмотреть сообщение

Самое простое — изменить размер стека, но при этом оно не самое правильное.

И тоже ясно, поэтому такой совет и дал.
Сформулирую иначе есть случаи в которых менять размер стека целесообразно по вашему? (если можно пример)



0



:)

Эксперт С++

4773 / 3267 / 497

Регистрация: 19.02.2013

Сообщений: 9,046

27.01.2014, 12:15

18

Цитата
Сообщение от mustimur
Посмотреть сообщение

есть случаи в которых менять размер стека целесообразно по вашему?

Если есть время и возможность переписать код, не увеличивая размер стека, то лучше так и сделать.
Иначе:
1. Когда есть готовая программа, требующая бОльшего стека.
2. Использование памяти на стеке быстрее, чем частое выделение/освобождение в куче. Хотя даже в этом случае можно выделить достаточный буфер в куче один раз и использовать его. Т.е. по сути сделать свой стек

с блекджеком

в куче.



0



320 / 225 / 74

Регистрация: 22.11.2013

Сообщений: 865

Записей в блоге: 1

27.01.2014, 12:59

19

Цитата
Сообщение от Tulosba
Посмотреть сообщение

Если есть время и возможность переписать код, не увеличивая размер стека, то лучше так и сделать.

Спасибо, в принципе так и думал



0



15 / 15 / 7

Регистрация: 20.11.2013

Сообщений: 92

27.01.2014, 16:01

20

Цитата
Сообщение от Tulosba
Посмотреть сообщение

mustimur, решений проблемы может быть несколько. Самое простое — изменить размер стека, но при этом оно не самое правильное.

Скажите, пожалуйста, почему изменять размер стека не самое целесообразное решение? И почему его лучше вообще не трогать? Если я правильно понимаю, то в защищенном режиме процессора ОС(в частности Windows 32bit), предоставляет памяти 4Гб, и если речь идет об объектах разумных размеров (скажем, до 100 мб), то для повышения быстродействия можно было бы использовать увеличенный стек, повысив тем самым скорость работы в 2 раза, по сравнению с кучей? Тогда по каким причинам так не поступают?



0



Если вы столкнулись с ошибкой STATUS_STACK_OVERFLOW (0xC00000FD) в Windows, значит, произошло переполнение стека. Подобная ситуация может возникнуть в пользовательских потоках, если какая-либо функция задействует большое количество локальных переменных или использует рекурсивные запросы.

Что это такое?

Стеком называется область памяти, предназначенная для хранения локальных переменных и адресов возврата функций. Когда происходит вызов какой-либо функции, она резервирует место для своих переменных и записывает адрес, по которому будет возвращена по окончании работы. Закончив операцию, функция высвобождает пространство и передает управление по заданному адресу. Следовательно, стек функционирует по принципу LIFO (last in, first out) – последний пришел, первый ушел.

Переполнение стека – это сигнал, когда функция пытается выделить больше памяти, чем есть в свободном доступе. Причин этому может быть несколько:

  • Она задействует чрезмерно много локальных переменных, занимающих лишнее место.
  • Вызывает себя рекурсивно без условия выхода или с недостаточным его значением, что приводит к бесконечной циклической рекурсии и увеличению стека.
  • Не может расширить пространство, потому что файл подкачки переполнен или система не может выделить дополнительные страницы памяти.

Когда происходит подобная проблема, система генерирует сообщение STATUS_STACK_OVERFLOW и завершает поток или приложение с ошибкой.

Как исправить?

Для устранения неисправности STATUS_STACK_OVERFLOW необходимо устранить причину переполнения. В зависимости от того, где и как возникает ошибка, можно применить различные методы решения:

  • Если ошибка наблюдается в вашем приложении или коде, следует проверить логику функций и уменьшить количество локальных переменных либо глубину рекурсии. Также можно использовать другие структуры данных вместо стека, например, очередь или список.
  • Если ошибка встречается в чужом приложении или коде, следует связаться с разработчиком или поставщиком для получения обновления или исправления.

    Можно также попробовать запустить программу в режиме совместимости или с другими опциями.

  • Если причиной сбоя является недостаточный объем памяти или файла подкачки, необходимо освободить место на диске или увеличить размер этого элемента. Кроме того, попробуйте закрыть другие процессы, потребляющие много ресурсов.
  • Если ошибка возникает из-за повреждения системных файлов или реестра, необходимо просканировать и восстановить систему с помощью утилит sfc /scannow и dism /online /cleanup-image /restorehealth. Также можно попробовать сделать бэкап из точки восстановления.

С помощью этих рекомендаций вы сможете избавиться от ошибки STATUS_STACK_OVERFLOW и предотвратить ее появление в будущем.

Понравилась статья? Поделить с друзьями:
  • Как в андроиде найти заблокированные номера телефона
  • Как найти джека в геншин импакт
  • Как найти купоны на вайлдберриз
  • Как составить табель если был простой
  • Как найти элемент последовательности с наименьшим значением