Где, кроме стека, может размещаться структура в Swift?

Ответ

По умолчанию экземпляры структур (value types) размещаются в стеке. Однако они могут быть перемещены в кучу (heap) в следующих случаях:

  1. Когда структура является свойством класса. Объект класса живет в куче, и все его свойства, включая структуры, размещаются там же.
  2. Когда структура захватывается escaping-замыканием. Замыкание, которое может пережить контекст, в котором оно создано, и его захваченные значения размещаются в куче.
  3. При использовании с existential типами (протоколами). Когда структура присваивается переменной типа протокола (например, var item: SomeProtocol), она упаковывается в existential container, который может использовать кучу.
  4. При работе с небезопасными указателями или внешними функциями, которые явно требуют выделения в куче.

Пример:

// 1. Структура как свойство класса → куча
class Container {
    var data: MyStruct // MyStruct размещается в куче вместе с объектом Container
}

// 2. Захват escaping-замыканием → куча
func createEscapingClosure() -> () -> Void {
    var capturedStruct = MyStruct(value: 10)
    return { // Замыкание может быть вызвано позже
        print(capturedStruct.value) // capturedStruct перемещена в кучу
    }
}

struct MyStruct {
    var value: Int
}

Почему это важно: Размещение в куче влечет накладные расходы на выделение/освобождение памяти и подсчет ссылок (для захваченных значений). Понимание этого помогает оптимизировать производительность, минимизируя неожиданные аллокации в куче.

Ответ 18+ 🔞

Ну, вот смотри, все эти умники кричат: «Структуры — они в стеке, быстро, эффективно, красота!» Ага, щас. Как будто в Свифте всё так просто, блядь. На деле-то эта хуйня может вылезти в кучу, когда ты совсем не ждёшь, и потом сидишь, чешешь репу — откуда просадки перформанса.

Так вот, слушай сюда, основные причины, почему твоя милая, стековая структурка вдруг начинает пастись в куче, как корова на лугу:

  1. Пристроилась к классу. Ну, тут всё логично, ёпта. Класс — он как богатый дядя, живёт в куче в своём хороме. И если твоя структура стала его свойством, то она переезжает к нему, на ПМЖ в кучу. Без вариантов. Ты ж не будешь её через забор кидать каждый раз, когда нужно обратиться.

  2. Её захапало escaping-замыкание. Вот это, сука, самый подлый случай. Смотри: сделал ты локальную переменную-структуру, передал её в замыкание, а замыкание это — убегающее (escaping). То есть его могут вызвать потом, когда твоя функция уже давно кончилась. И компилятор такой: «Ну, братан, раз уж ты так хочешь, чтобы эта структура жила дольше своего стека, держи — переехала в кучу». И всё, приехали. Теперь у неё там своя маленькая жизнь с подсчётом ссылок.

  3. Полезла в протоколы (existential типы). О, это классика! Объявил переменную типа протокола: var shit: SomeProtocol. И пытаешься запихнуть туда свою структуру. Компилятор хитро так ухмыляется: «А я, блядь, не знаю на этапе компиляции, какого она размера. Может, она большая, может, маленькая. Ладно, заверну в специальную коробочку (existential container), и если не влезет — отправим на склад, то есть в кучу». И отправляет, зараза.

  4. Прямой приказ. Ну, тут уже сам виноват. Работаешь с небезопасными указателями или какими-нибудь старыми С-шными функциями, которые прямо говорят: «Дай мне память из кучи!». Ну и даёшь, чё уж там.

Вот, смотри, наглядненько:

// 1. Пристроилась к классу — сразу в кучу, как пить дать.
class Container {
    var data: MyStruct // MyStruct теперь живёт в куче, вместе с этим Container'ом.
}

// 2. Захапана escaping-замыканием — тоже в кучу, прощай, стек.
func createEscapingClosure() -> () -> Void {
    var capturedStruct = MyStruct(value: 10) // Вроде в стеке...
    return { // А вот и нет, блядь!
        print(capturedStruct.value) // capturedStruct теперь в куче, потому что замыкание может убежать.
    }
}

struct MyStruct {
    var value: Int
}

А нахуя это знать-то? Да затем, что кучная жизнь — это дорого, ёпта! Аллокация, деаллокация, подсчёт ссылок — это всё оверхеды. Если ты пишешь высокопроизводительный код и думаешь, что хитришь со структурами, а они тебе втихую в куче живут — это пиздец. Понимание этих моментов помогает не наступать на эти грабли и не охуевать потом от профайлера.