Память
Иерархия памяти
Чем ближе память к процессору, тем она быстрее и меньше:
- Регистры процессора — единицы наносекунд, десятки штук.
- Кэши L1/L2/L3 — прозрачны для программиста, но объясняют, почему последовательный проход по
Arrayбыстрее, чем прыжки по связному списку. - Оперативная память (RAM) — энергозависимая: всё теряется при перезапуске процесса. На iPhone её от 6 до 12 ГБ, и приложение получает лишь часть.
- Флеш-накопитель — долговременное хранилище: бандл приложения, Documents, Core Data/SwiftData, UserDefaults.
Стек и куча — то, о чём спросят
Внутри RAM у процесса есть две области, важные для Swift:
- Стек — у каждого потока свой (главный поток — 1 МБ на iOS, фоновые по умолчанию 512 КБ). Выделение — просто сдвиг указателя, освобождение автоматическое при выходе из функции. Сюда попадают локальные переменные и value types (
struct,enum), если компилятор может вычислить их размер и время жизни. - Куча — общая для всех потоков, выделение через
malloc, освобождение через ARC. Здесь живут все экземплярыclass, буферыArray/String/Dictionary, замыкания, захватившие переменные, и value types, которые «сбежали» (например, struct, сохранённый вany Protocol, если не помещается в inline-буфер).
struct Point { var x: Double; var y: Double } // значение — обычно на стеке
final class Node { var next: Node? } // объект — всегда в куче
func demo() {
let p = Point(x: 1, y: 2) // 16 байт в кадре стека, исчезнут при выходе
let n = Node() // malloc + счётчик ссылок; умрёт при count == 0
var points = [p] // буфер массива — в куче, хотя Array — struct
points.append(Point(x: 3, y: 4))
_ = n
}
Почему это важно для iOS
- Куча дороже: аллокация, атомарные
retain/release, возможные гонки. Поэтому Apple советует начинать соstruct. - Память приложения ограничена: при превышении лимита система присылает
didReceiveMemoryWarning, а затем убивает процесс (jetsam). ОтсюдаNSCache, даунсэмплинг картинок, профилирование в Instruments (Allocations, Leaks). - Глубокая рекурсия переполняет стек — краш
EXC_BAD_ACCESSбез исключения.