Когда выделяется память на стек и на кучу — на этапе компиляции или рантайма
Что проверяют
Отличаете ли вы решение о размещении от самого выделения памяти и знаете ли, как это устроено в Swift. Следом почти всегда спрашивают, правда ли, что struct всегда живёт на стеке, а class в куче.
Как отвечать
Короткий ответ: и то и другое выделяется в рантайме. На этапе компиляции решается только планировка.
- стек: компилятор заранее вычисляет размер кадра функции и смещения локальных переменных. Сама память занимается при вызове, когда сдвигается указатель стека, и освобождается при возврате. Стек потока создаётся вместе с потоком, у вторичных потоков он по умолчанию меньше, чем у главного;
- куча: выделение идёт в рантайме через аллокатор. Для экземпляра класса Swift вызывает
swift_allocObject, объект получает заголовок с указателем на метаданные и счётчиком ссылок; - статические данные: глобальные константы и переменные лежат в сегментах бинарника, их расположение фиксирует линковщик. Статические свойства и глобальные переменные вне
main.swiftпри этом инициализируются лениво, при первом обращении.
Дальше про Swift. Значимые типы часто оказываются на стеке или в регистрах, но не всегда: struct, захваченная escaping-замыканием, лежащая в свойстве класса или в экзистенциальном контейнере any Protocol крупнее его встроенного буфера, уедет в кучу. Array, String и Dictionary сами структуры, но их содержимое хранится в куче с copy-on-write. Бывает и наоборот: оптимизатор может разместить на стеке экземпляр класса, который не покидает функцию.
Цена кучи не только в выделении: к ней добавляется атомарный подсчёт ссылок ARC, где retain и release вставляет компилятор, и худшая локальность данных.
Где спотыкаются
Отвечают «стек на этапе компиляции, куча в рантайме». Компилятор знает размер кадра, но память под него появляется только при вызове.
Жёстко связывают struct со стеком, а class с кучей. Интервьюер тут же попросит пример исключения, и хорошо бы его знать.
Путают ARC с ручными malloc и free или со сборщиком мусора. В Swift объект освобождается детерминированно, когда счётчик сильных ссылок падает до нуля, а утечки возникают из-за циклов сильных ссылок.