Ответ
Стек вызовов — это область памяти, выделяемая для каждого потока, где хранятся локальные переменные, аргументы функций и адреса возврата. Его размер жестко ограничен и обычно невелик.
Ключевые аспекты:
- Типичный размер: По умолчанию в Linux — 8 МБ (можно проверить и изменить командой
ulimit -s). В Windows для основного потока — 1 МБ, для создаваемых потоков — по умолчанию тоже 1 МБ, но его можно задать вstd::thread. - Причины переполнения (Stack Overflow):
- Глубокая или бесконечная рекурсия.
- Создание больших объектов на стеке (например,
std::array<int, 1000000>илиchar buffer[1024 * 1024]). - Много вложенных вызовов функций с большим количеством локальных переменных.
Пример проблемного кода:
void recursiveFunction(int depth) {
int localArray[1000]; // Выделяет 4 КБ на стеке при каждом вызове
// ... какая-то работа
if (depth > 0) {
recursiveFunction(depth - 1); // При depth > 2000 почти гарантированно переполнит стек
}
}
Стратегии предотвращения и решения:
- Избегать глубокой рекурсии. Переписывать рекурсивные алгоритмы на итеративные, если глубина может быть большой.
- Выделять большие данные в куче. Использовать
std::vector,std::make_uniqueилиnew. - Явно увеличивать размер стека потока. Например, в POSIX с помощью
pthread_attr_setstacksize, а в C++11 — передавая нужный размер в конструкторstd::thread. - Использовать
-fstack-usage(GCC/Clang) для анализа использования стека функциями.
Практический пример замены рекурсии на итерацию:
// Рекурсивный обход (опасен при большой глубине)
void traverseTreeRecursive(TreeNode* node) {
if (!node) return;
process(node);
traverseTreeRecursive(node->left);
traverseTreeRecursive(node->right);
}
// Итеративный обход с использованием стека в куче (std::stack)
void traverseTreeIterative(TreeNode* root) {
std::stack<TreeNode*> nodeStack;
nodeStack.push(root);
while (!nodeStack.empty()) {
TreeNode* current = nodeStack.top();
nodeStack.pop();
if (current) {
process(current);
nodeStack.push(current->right); // Сначала кладем правый
nodeStack.push(current->left); // Затем левый
}
}
}