Ответ
Нет, не всегда. Хотя семантика ссылочных типов (классов) в Swift предполагает размещение в куче, компилятор проводит агрессивные оптимизации, которые могут изменить это поведение.
Стандартный случай: Куча
По умолчанию экземпляры классов создаются в куче, что позволяет иметь несколько ссылок на один объект и управлять памятью через ARC.
class StandardClass { var value = 10 }
let obj = StandardClass() // Экземпляр, скорее всего, в куче
let ref = obj // Две ссылки на один объект в куче
Оптимизации компилятора (Stack Promotion)
Компилятор Swift (в режиме -O) может переместить объект из кучи в стек, если может доказать безопасность этого:
- Локальная область видимости: Объект создается и не покидает пределы функции.
- Отсутствие escape-анализа: На объект не создается внешних ссылок, которые переживут функцию.
- Размер и простота: Объект не слишком велик и не имеет сложных зависимостей.
func calculate() -> Int {
class LocalCalculator { var a = 5; var b = 3 }
let calculator = LocalCalculator() // Может быть оптимизирован в стек!
return calculator.a + calculator.b
}
// 'calculator' не используется вне функции -> кандидат на оптимизацию.
Ключевые исключения и гарантии
- Явное требование кучи: Если класс передается как
@escapingзамыкание, сохраняется в свойство или возвращается из функции — он гарантированно будет в куче. - Value-типы (struct, enum): Почти всегда размещаются в стеке (или внутри другого объекта), если не обернуты в
Box-класс (например, при использовании с@escaping).
Вывод: Размещение в куче — это семантика, а не строгая гарантия реализации. Компилятор может оптимизировать размещение для повышения производительности, не меняя наблюдаемого поведения программы.
Ответ 18+ 🔞
А, вот это интересный вопрос, блядь! Ну, типа, все знают, что классы — это куча, ссылки, ARC, вся эта хуйня. Но не всё так однозначно, ёпта!
Смотри, в теории да, ты прав. Создал экземпляр класса — и он, сука, полетел в кучу. Это база, это семантика языка, чтобы можно было на один объект десять ссылок повесить.
class MyClass { var x = 42 }
let a = MyClass() // Вроде как в куче
let b = a // Та же самая жопа, только в профиль
Но компилятор-то Swift — он не лыком шит, блядь! Он хитрожопый, как мартышка с гранатой. Включил оптимизацию (-O), и он начинает думать: «А нахуй мне тут кучу городить?».
Оптимизация «А давай в стек!» (Stack Promotion)
Если компилятор видит, что объект живёт только внутри функции и никуда не сбегает, он может его на стек запихнуть. Типа, зачем тебе динамическая память, если ты тут локально посчитал и выкинул?
func doStuff() -> Int {
class TempHelper { var y = 10 }
let helper = TempHelper() // Этому пацану, возможно, в куче даже не светит!
return helper.y * 2
}
// helper тут же помирает, зачем ему вечность в куче? В стек его, в рот меня чих-пых!
Но есть моменты, когда оптимизатор машет лапкой и говорит: «Нет, браток, тут только куча, иди нахуй»:
- Если объект сбегает из функции (
@escapingзамыкание, блядь). - Если его в свойство какого-нибудь другого долгоживущего урода запихивают.
- Если он из функции возвращается наружу.
Тут уже никуда не денешься — лети, милок, в кучу, там тебя ARC будет нежно обнимать.
А вот структуры (struct) и перечисления (enum) — это вообще другая история, блядь. Они по умолчанию в стеке или внутри родителя сидят, как мыши под веником. Пока ты их в какой-нибудь @escaping контекст не сунешь — тогда их, бедолаг, в класс-обёртку (Box) запакуют и тоже в кучу отправят. Жесть, конечно.
Так что вывод, сука, какой? Да, семантика — куча. Но реализация — это уже поле для манёвров компилятора. Он может сделать финт ушами и разместить объект там, где выгоднее для скорости, если это не ломает логику. Главное, чтобы программа вела себя так, как будто он в куче, а где он на самом деле — это уже детали, волнение ебать.