Сколько стеков создается в iOS приложении
Что проверяют
Понимаете ли вы связь стека с потоком и знаете ли реальные размеры, а не абстрактное «стек вызовов». Фиксированного числа здесь нет, и интервьюер ждёт именно этого вывода. Следом обычно спрашивают про переполнение стека и про то, есть ли свой стек у задач Swift Concurrency.
Как отвечать
Стек в iOS принадлежит потоку: сколько потоков живёт в процессе, столько и стеков. Ответ «один» или «три» неверен, число меняется за время работы приложения.
- главный поток: на устройстве стек 1 МБ, создаётся при запуске процесса, на нём крутится
RunLoopи весь UIKit; - вторичные потоки: по умолчанию 512 КБ. Для
Threadразмер задаётся черезstackSizeдо вызоваstart(), минимум 16 КБ и кратно 4 КБ; - системные потоки: даже пустое приложение после запуска держит несколько потоков, например
com.apple.uikit.eventfetch-threadи рабочие потоки GCD. Их видно в Debug Navigator или командойthread listв LLDB; - GCD: очередь не равна потоку. Задачи выполняются на потоках из общего пула, и стек есть у потока пула, а не у каждой задачи;
- Swift Concurrency: у
Taskнет собственного стека. Кадрыasync-функций хранятся в куче, а выполняются на кооперативном пуле, где потоков примерно столько, сколько ядер.
Стоит добавить, что память под стек резервируется виртуально и расходуется по мере надобности, а за переполнением следит guard-страница: глубокая рекурсия или огромная структура на стеке дают EXC_BAD_ACCESS.
Где спотыкаются
Называют конкретное число. Правильный ответ: по стеку на поток, а потоков в живом приложении обычно больше, чем кажется.
Смешивают стек вызовов и навигационный стек UINavigationController. Если не уверены, какой имеется в виду, уточните: это выглядит лучше, чем уверенный ответ не про то.
Считают, что каждый DispatchQueue.global().async создаёт новый поток. Пул переиспользует потоки, но если задачи в нём блокируются на семафорах или синхронном I/O, GCD добавляет новые, и начинается thread explosion: десятки стеков и постоянные переключения контекста.