Отладка ошибок StackOverflow
Исключение StackOverflowException, которое возникает при переполнении стека выполнения из-за чрезмерного количества вложенных вызовов метода.
Например, рассмотрим представленное ниже приложение:
using System; namespace temp < class Program < static void Main(string[] args) < Main(args); // Oops, this recursion won't stop. >> >
Метод Main будет постоянно вызывать сам себя до тех пор, пока в стеке не закончится место. После этого продолжение будет невозможно и возникнет исключение StackOverflowException.
> dotnet run Stack overflow.
В .NET 5 и более поздних версий стек вызовов выводится на консоль.
В этой статье описывается отладка ситуаций переполнения стека с использованием lldb. Если вы работаете в Windows, для отладки приложения рекомендуется использовать Visual Studio или Visual Studio Code.
Пример
- Запуск приложения, для которого настроено получение дампа при аварийном завершении.
> export DOTNET_DbgEnableMiniDump=1 > dotnet run Stack overflow. Writing minidump with heap to file /tmp/coredump.6412 Written 58191872 bytes (14207 pages) to core file
Примечание .NET 6 стандартизует префикс DOTNET_ вместо COMPlus_ для переменных среды, которые настраивают поведение .NET во время выполнения. Но префикс COMPlus_ будет и дальше работать. Если вы используете предыдущую версию среды выполнения .NET, следует и дальше использовать префикс COMPlus_ для переменных среды.
dotnet-sos install
lldb --core /temp/coredump.6412 (lldb) bt . frame #261930: 0x00007f59b40900cc frame #261931: 0x00007f59b40900cc frame #261932: 0x00007f59b40900cc frame #261933: 0x00007f59b40900cc frame #261934: 0x00007f59b40900cc frame #261935: 0x00007f5a2d4a080f libcoreclr.so`CallDescrWorkerInternal at unixasmmacrosamd64.inc:867 frame #261936: 0x00007f5a2d3cc4c3 libcoreclr.so`MethodDescCallSite::CallTargetWorker(unsigned long const*, unsigned long*, int) at callhelpers.cpp:70 frame #261937: 0x00007f5a2d3cc468 libcoreclr.so`MethodDescCallSite::CallTargetWorker(this=, pArguments=0x00007ffe8222e7b0, pReturnValue=0x0000000000000000, cbReturnValue=0) at callhelpers.cpp:604 frame #261938: 0x00007f5a2d4b6182 libcoreclr.so`RunMain(MethodDesc*, short, int*, PtrArray**) [inlined] MethodDescCallSite::Call(this=, pArguments=) at callhelpers.h:468 .
(lldb) ip2md 0x00007f59b40900cc MethodDesc: 00007f59b413ffa8 Method Name: temp.Program.Main(System.String[]) Class: 00007f59b4181d40 MethodTable: 00007f59b4190020 mdToken: 0000000006000001 Module: 00007f59b413dbf8 IsJitted: yes Current CodeAddr: 00007f59b40900a0 Version History: ILCodeVersion: 0000000000000000 ReJIT ID: 0 IL Addr: 0000000000000000 CodeAddr: 00007f59b40900a0 (MinOptJitted) NativeCodeVersion: 0000000000000000 Source file: /temp/Program.cs @ 9
См. также:
- Общие сведения о дампах в .NET
- Отладка дампов Linux
- Расширение отладки SOS для .NET
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Ошибка «Stack overflow» — что это и как ее избежать?
обычно это значит что есть проблемы с рекурсией, в большинстве случаев когда задаётся этот вопрос — нету условия выхода из рекурсии.
3 фев 2017 в 20:33
Еще появляется, когда вы объявляете слишком большой локальный массив (внутри функции). Обычно размер стека ограничен несколькими мегабайтами.
3 фев 2017 в 20:42
Обычно эта ошибка бывает из-за @PashaPash.
– user207618
4 фев 2017 в 5:08
@Other, почему?
4 фев 2017 в 9:19
@maestro, этот пользователь умудрился сломать http://ru.stackoverflow.com/ , ирония 🙂
– user207618
4 фев 2017 в 9:26
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Это означает, что в стеке недостаточно места.
Причины — например, слишком глубокая рекурсия (редко), или слишком большие локальные переменные (куда чаще), или и то и другое сразу 🙂
Как избавиться? Опять же, можно просто в настройках компилятора поднять размер стека.
Но надежнее и лучше — посмотреть, нет ли слишком глубокой (вплоть до бесконечности) рекурсии, заменить локальные массивы на выделяемые динамически.
int f() < int a[1000000];
практически гарантированно даст переполнение стека. В отличие от
int f() < int * a = new int[1000000]; // Только не забудьте потом удалить.
vector a(1000000);
Словом, смотрите, кто съедает много стековой памяти, и избавляйтесь от него.
Отслеживать
ответ дан 3 фев 2017 в 20:47
219k 15 15 золотых знаков 119 119 серебряных знаков 230 230 бронзовых знаков
Про стек и другие типы данных:
- Стековые данные. На них память выделяется при заходе в процедуру и освобождается при её завершении. Максимальный размер стека программы составляет 1 GB и для 32-битных, и для 64-битных приложений. (Размерстека задаётся линковщиком и по умолчанию составляет 1 MB)
- Статические данные. Ограничение накладывается на размер самого исходного кода программы и размер статически выделяемой памяти. В языке C++ такие данные обычно представлены переменными, объявленными на глобальном уровне вне процедур. Как для 32-битных, так и для 64-битных программ, ограничение на размер статически выделяемой памяти равно 2 GB.
- Динамические данные. Это данные, память на которые динамически выделяется во время исполнения программы. В C++ такое выделение обычно осуществляется функцией malloc или оператором new. В 32-битных программах размер динамически выделяемой памяти ограничен 2 GB, в 64-битных — 8 TB.
У 32-битного приложения запущенного в 32-битной Windows суммарный размер всех перечисленных типов данных не должен превышать 2 GB. (Практически ограничение равно 1.75GB из-за требований к памяти самой операционной системы) 32-битная программа, собранная с ключом /LARGEADDRESSAWARE:YES может выделять до 3-х гигабайт памяти, если 32-битная операционная система Windows запущена с ключом /3gb. Эта же 32-битная программа, запущенная на 64-битной системе, может выделить почти 4 GB памяти (на практике около 3.5 GB).
Ограничения на максимальный размер статически-выделяемой и стековой памяти одинаковы для 32-х и 64-х битных Windows приложений. Это связано с форматом типа файлов Portable Executable (PE), который используется в Windows для описания exe и dll файлов. Статические и стековые данные располагаются в первых 2-х GB адресного пространства приложения. Стоит помнить, что данные ограничения накладываются самой операционной системой и не зависят от используемого компилятора.
- Как написал коллега [Harry] в ответе.
Это означает, что в стеке недостаточно места.
- Зная выше описанные ограничения и возможные причины появления данной ошибки, Вы всегда можете проектировать Ваши решения, что бы избегать подобных проблем.
Что такое StackOverflow ошибка: раскрываем тайну
![]()
В мире программистов ошибка «stack overflow» очень известн а б лагодаря тому, что этот вид ошибки довольно распространен. А сам термин «stack overflow» известен еще больше , чем ошибка, благодаря одноименному англоязычному ресурсу «StackOverflow». Это сообщество программистов международного масштаба , и еще куча всего интересного. Поэтому не нужно путать ошибку « stack overflow » и веб-ресурс с таким же названием. В нашей статье речь пойдет об ошибке.
Ошибка «stack overflow» связана с переполнением стека. Она появляется в том случае, когда в стеке должно сохранит ь ся больше информации, чем он может уместить. Объем памяти стека задает программист при запуске программы. Если в процессе выполнения программы стек переполняется, тогда возникает ошибка « stack overflow » и программа аварийно завершает работу. Причин возникновения подобной ошибки может быть несколько.
Ошибка « stack overflow »
- бесконечная рекурсия;
- глубокая рекурсия;
- проблемы с переменными в стеке.
Бесконечная рекурсия и ошибка «stack overflow»
- забывает прописывать условие для выхода из рекурсии;
- пишет неосознанную косвенную рекурсию.
Глубокая рекурсия и ошибка «stack overflow»
- отыскать другой программный алгоритм для решения поставленной задачи, чтобы избежать применени я рекурсии;
- «вынести» рекурсию за пределы аппаратного стека в динамический;
- и другое.
Проблемы с переменными в стеке и ошибка «stack overflow»
Если взглянуть на популярность возникновения «stack overflow error», то причина с проблемными переменными в стеке стоит на первом месте. Кроется она в том, что программист изначально выделяет слишком много памяти локальной переменной.
Например:
int function()
double b[1000000]
>
В данном случае может возникнуть такая ситуация, что массиву потребуется объем памяти, который стек не способен будет обеспечить, а значит , возникнет ошибка «stack overflow».
Заключение
Ошибка « stack overflow » возникает довольно часто. Каждый конкретный случай ее возникновения требует собственного решения. Одна причина объединяет возникновение такой ошибки — невнимательность программиста. Если « stack overflow error » возникла, значит , программист где-то что-то упустил или не доглядел.
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
Что на самом деле вызывает ошибку StackOverflow в Java?
StackOverflowError просто сигнализирует о том, что памяти больше нет. Он расширяет класс VirtualMachineError, что указывает на то, что JVM (виртуальная машина Java) повреждена или у нее закончились ресурсы и она не может работать.
Если у вас есть такая функция, как:
int myFunction() < // ваш код myFunction(); >
В приведенном выше коде myFunction() будет продолжать называть себя, все глубже и глубже, и когда пространство, используемое для отслеживания того, какие функции вы находитесь, заполнено, вы получаете ошибку stackoverflow. Общей причиной переполнения стека является плохой рекурсивный вызов. Как правило, это вызвано, когда ваши рекурсивные функции не имеют правильного условия завершения, поэтому он заканчивается тем, что навсегда называет себя.
Причина использования StackOverflowError
Параметры и локальные переменные выделяются в стеке. Стек обычно находится в верхнем конце вашего адресного пространства, и, поскольку он используется, он направляется к нижней части адресного пространства. У вашего процесса также есть куча, которая живет в нижней части вашего процесса. Когда вы выделяете память, эта куча может расти в верхнем конце вашего адресного пространства. Как вы можете видеть, существует вероятность того, что куча «столкнется» со стеклом. Если нет места для нового стека кадров, StackOverflowError вызывается виртуальной машиной Java (JVM).
Если стек заполнен, вы не можете нажать, если вы это сделаете, вы получите ошибку переполнения стека.
Если стек пуст, вы не можете поп, если вы это сделаете, вы получите ошибку стека стека.
Что такое stacktrace?
Столбец - очень полезный инструмент для отладки. Это список вызовов метода, в которых приложение было посередине, когда было выбрано исключение. Это очень полезно, потому что оно не только показывает вам, где произошла ошибка, но также и то, как программа оказалась в этом месте кода.
Столбец - очень полезный инструмент для отладки. Это список вызовов метода, в которых приложение было посередине, когда было выбрано исключение. Это очень полезно, потому что оно не только показывает вам, где произошла ошибка, но также и то, как программа оказалась в этом месте кода.