Существуют ли ограничения по размеру стека вызовов?

«Существуют ли ограничения по размеру стека вызовов?» — вопрос из категории Алгоритмы и структуры данных, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, стек вызовов (call stack) имеет ограниченный размер, выделяемый операционной системой для каждого потока.

  • В iOS/macOS: основной поток обычно имеет стек размером 1 МБ, а фоновые потоки — 512 КБ. Эти значения могут незначительно варьироваться в зависимости от системы.
  • Причина ограничения: предотвращение неконтролируемого потребления памяти и обеспечение изоляции потоков.
  • Последствия переполнения: при превышении лимита (например, из-за бесконечной или очень глубокой рекурсии) возникает ошибка EXC_BAD_ACCESS (EXC_I386_GPFLT) или Stack Overflow, приводящая к крашу приложения.

Пример, вызывающий переполнение:

func recursiveFunction(depth: Int) {
    var largeLocalArray = Array(repeating: 0, count: 1000) // Потребляет место в стеке
    recursiveFunction(depth: depth + 1) // Рекурсивный вызов без условия выхода
}
// Вызов: recursiveFunction(depth: 0)

Как избежать переполнения стека:

  1. Заменяйте глубокую рекурсию на итеративные алгоритмы (циклы).
  2. Для хранения больших объемов данных используйте кучу (heap), а не стек (например, храните большие массивы как свойства класса, а не как локальные переменные).
  3. В исключительных случаях для собственных потоков можно изменить размер стека с помощью pthread_attr_setstacksize, но это считается антипаттерном и требует осторожности.