Быстрое понимание стека / кучи

Я хочу понять, что хранится в стеке / куче в Swift. У меня есть приблизительная оценка: все, что вы печатаете и адрес памяти, - это не значения, они хранятся в стеке, и то, что распечатывается как значения, они находятся в куче, в основном в соответствии со значениями и ссылочными типами. Я совершенно не прав? И, возможно, вы могли бы представить визуальное представление стека / кучи?

4 ответа

Как уже было сказано, ссылочные типы хранятся в куче, а значения в стеке…

Здесь я хочу дать объяснение, почему...

Стек и куча?

Стек используется для статического выделения памяти и Heap для динамического выделения памяти, оба хранятся в оперативной памяти компьютера.

Переменные, размещенные в стеке, хранятся непосредственно в памяти, и доступ к этой памяти очень быстрый, и с ее распределением происходит компиляция программы. Когда функция или метод вызывает другую функцию, которая, в свою очередь, вызывает другую функцию и т. Д., Выполнение всех этих функций приостанавливается до тех пор, пока самая последняя функция не вернет свое значение. Стек всегда резервируется в порядке LIFO, последний зарезервированный блок всегда является следующим блоком, который должен быть освобожден. Это действительно упрощает отслеживание стека, освобождение блока из стека - всего лишь настройка одного указателя.

введите описание изображения здесь

Переменным, выделенным в куче, выделяется их память во время выполнения, и доступ к этой памяти немного медленнее, но размер кучи ограничен только размером виртуальной памяти. Элемент кучи не имеет зависимостей друг от друга и всегда может быть доступен случайным образом в любое время. Вы можете выделить блок в любое время и освободить его в любое время. Это значительно усложняет отслеживание того, какие части кучи выделены или свободны в любой момент времени.

Классы (ссылочные типы) размещаются в куче, типы значений (такие как Struct, String, Int, Bool и т. Д.) Находятся в стеке. Посмотрите эту тему для более подробных ответов: Почему стоит выбрать Struct Over Class?

Стек против кучи

Stackявляется частью потока. Он состоит из фреймов методов (функций) в порядке LIFO. Фрейм метода содержит локальные переменные. Фактически это трассировка стека методов, которую вы видите во время отладки или анализа ошибки <sup>[О программе]</sup> . Создается новая копия ценности - это может быть копия reference type адрес или копия value type(Копирование по механизму записи). Потоковая безопасность <sup>[О программе]</sup>

Heapдругая часть памяти, где ARC <sup>[About]</sup> вступает в игру. Здесь требуется больше времени, чтобы выделить память (найти подходящее место и распределить его синхронно). Создана новая копия справки

Эти концепции такие же, как [иллюстрация JVM]

Xcode предлагает следующий вариант с использованием Debug Memory Graph * Чтобы увидеть использование Backtrace Malloc Stack Logging

[Значение и тип ссылки]

[Класс против структуры]

Обычно, когда мы задаем такой вопрос (это стек или куча), мы заботимся о производительности и мотивированы желанием избежать чрезмерных затрат на выделение кучи. Следование общему правилу о том, что «ссылочные типы размещаются в куче, а типы значений — в стеке», может привести к неоптимальным проектным решениям и требует дальнейшего обсуждения.

Можно ошибочно заключить, что передача структур (типов значений) всегда быстрее, чем передача классов (ссылочных типов), потому что она никогда не требует выделения кучи. Оказывается, это не всегда верно.

Важным контрпримером являются типы протоколов, в которых конкретные полиморфные типы с семантикой значений (структуры) реализуют протокол, как в этом игрушечном примере:

      protocol Vehicle {
    var mileage: Double { get }
}

struct CombustionCar: Vehicle {
    let mpg: Double
    let isDiesel: Bool
    let isManual: Bool
    var fuelLevel: Double    // gallons
    var mileage: Double { fuelLevel * mpg }
}

struct ElectricCar: Vehicle {
    let mpge: Double
    var batteryLevel: Double // kWh
    var mileage: Double { batteryLevel * mpge / 33.7 }
}

func printMileage(vehicle: Vehicle) {
    print("\(vehicle.mileage)")
}

let datsun: Vehicle = CombustionCar(mpg: 18.19,
                                        isDiesel: false,
                                        isManual: false,
                                        fuelLevel: 12)
let tesla: Vehicle = ElectricCar(mpge: 132,
                                 batteryLevel: 50)
let vehicles: [Vehicle] = [datsun, tesla]
for vehicle in vehicles {
    printMileage(vehicle: vehicle)
}

Обратите внимание, чтоиобъекты имеют разные размеры, но мы можем смешивать их в массиветипы протоколов. В связи с этим возникает вопрос: не должны ли элементы контейнера массива быть одинакового размера? Как компилятор может вычислить смещение элемента массива, если он не всегда знает размер элемента во время компиляции?

Оказывается, под капотом довольно много логики. Компилятор Swift создаст так называемый файл . Это структура данных фиксированного размера, действующая как оболочка вокруг объекта. Именно этот контейнер передается вызову функции (помещается в стек) вместо фактической структуры.

состоит из пяти слов:

      |           |
|valueBuffer|
|           |
|    vwt    |
|    pwt    |

Первые три слова называются the, и именно здесь сохраняется фактическая структура. Ну, это если размер структуры больше трех слов - в таком случае компилятор выделит структуру в куче и сохранит ссылку на нее в:

          STACK                  STACK              HEAP

|   mpge     |         |  reference |-->|     mpg     |
|batteryLevel|         |            |   |   isDiesel  |
|            |         |            |   |   isManual  |
|    vwt     |         |     vwt    |   |   fuelLevel |
|    pwt     |         |     pwt    |

Таким образом, передача объекта типа протокола, подобного этому, в функцию может фактически потребовать выделения кучи. Компилятор выполнит распределение и скопирует значения, поэтому вы все равно получите семантику значений, но стоимость будет варьироваться в зависимости от того, состоит ли ваша структура из 3 слов или более. Это делает «типы значений в стеке, ссылочные типы в куче» не всегда правильными.

Другие вопросы по тегам