Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как устроена память в iOS?
Память в iOS строится на уровне процесса. Каждый iOS процесс получает собственное виртуальное адресное пространство, изолированное от других процессов благодаря MMU (Memory Management Unit).
Виртуальное адресное пространство
0xFFFFFFFF ┌──────────────────────────┐
│ Kernel Space │ (зарезервирована для системы)
│ (недоступна приложению)│
├──────────────────────────┤
│ Stack (растёт вниз ↓) │ (локальные переменные, параметры)
│ │
│ ↓ │
│ │
├──────────────────────────┤
│ Unused Memory │
│ │
│ ↑ │
│ │
│ Heap (растёт вверх ↑) │ (динамические объекты, массивы)
├──────────────────────────┤
│ .bss (неинициал. данные)│
│ .data (инициализированные данные)
│ .text (код, константы) │
│ │
0x00000000 └──────────────────────────┘
Главные компоненты
1. Stack (Стек)
Быстрая память для локальных переменных и параметров функций:
func example() {
let x = 10 // Stack
let y = 20 // Stack
var point = Point(x: 0, y: 0) // Stack (if struct)
} // ← автоматически удаляется
Характеристики:
- Линейное выделение (просто сдвигаем указатель)
- Автоматическое освобождение при выходе из scope
- Ограниченный размер (на iPhone ~1 MB)
- Очень быстрый доступ
- LIFO (Last In First Out)
func stackExample() {
let a = 1 // Stack pointer +4 bytes
let b = 2 // Stack pointer +4 bytes
let c = 3 // Stack pointer +4 bytes
// функция заканчивается
// Stack pointer -12 bytes (выход из всех трёх переменных)
}
2. Heap (Куча)
Динамическая память для объектов, которые живут дольше, чем функция:
class User { // Heap
let name: String // String данные в Heap
let age: Int
}
func example() {
let user = User(name: "John", age: 30)
// переменная user на Stack
// объект User в Heap
// переменная user содержит адрес объекта
}
// пользователь удаляется благодаря ARC
Характеристики:
- Выделение произвольного размера
- Требует управления (ARC в Swift)
- Медленнее, чем Stack
- Большой размер (~GB на современных iPhone)
- Фрагментируется со временем
Система управления памятью: ARC
ARC (Automatic Reference Counting) подсчитывает ссылки на объекты в Heap:
class Person {}
var p1 = Person() // refCount = 1
var p2 = p1 // refCount = 2
p1 = nil // refCount = 1
p2 = nil // refCount = 0 → объект удаляется из Heap
Retain cycles (утечки памяти)
class Parent {
var child: Child? // сильная ссылка
}
class Child {
var parent: Parent? // сильная ссылка
}
var p = Parent()
var c = Child()
p.child = c // Parent → Child
c.parent = p // Child → Parent
p = nil // refCount(Parent) = 1 (указывает Child)
c = nil // refCount(Child) = 1 (указывает Parent)
// УТЕЧКА ПАМЯТИ: оба объекта никогда не удалятся!
Решение: weak reference
class Parent {
var child: Child?
}
class Child {
weak var parent: Parent? // слабая ссылка!
}
var p = Parent()
var c = Child()
p.child = c
c.parent = p
p = nil // Parent удаляется (refCount = 0)
c = nil // Child удаляется (refCount = 0)
Детальная архитектура памяти
Text Segment (.text)
let PI = 3.14159 // константа в .text
func printHello() { // код функции в .text
print("Hello")
}
// .text — read-only, не может быть изменён
Data Segment (.data, .bss)
var globalCounter = 0 // .data (инициализирована нулём)
var staticArray: [Int] = [] // .data
// .bss используется для неинициализированных данных
Registers (регистры CPU)
Наиболее быстрая память — регистры процессора:
// Компилятор может поместить в регистр
let x = 1 + 2 // может быть в регистре
let y = x * 2 // может быть в регистре
Виды памяти и их скорость
Регистры: ████ наносекунды (1-2 цикла)
L1 Cache: ███ наносекунды (2-4 цикла)
L2 Cache: ██ наносекунды (10 циклов)
Stack: ██ наносекунды (50 циклов)
Heap: ░ микросекунды (100+ циклов)
Disk/Network: ░░░ миллисекунды (1,000,000+ циклов)
Управление памятью в Swift
Value Types (на Stack)
struct Point { // Value Type
let x: Int // Stack
let y: Int // Stack
}
func test() {
let p = Point(x: 0, y: 0) // весь Point на Stack
} // p удаляется со Stack
Reference Types (на Heap)
class Location { // Reference Type
let x: Int // Heap
let y: Int // Heap
}
func test() {
let loc = Location(x: 0, y: 0) // объект в Heap
} // loc переменная исчезает, объект удаляется через ARC
Memory Footprint
var array = [1, 2, 3] // переменная на Stack, массив в Heap
print(MemoryLayout<[Int]>.size) // 16 или 24 байт на Stack
var string = "Hello" // переменная на Stack, данные в Heap
print(MemoryLayout<String>.size) // 24 байт на Stack
var number = 42 // полностью на Stack
print(MemoryLayout<Int>.size) // 8 байт на Stack
Утечки памяти: как найти
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// ❌ УТЕЧКА: closure захватывает self strongly
DispatchQueue.main.asyncAfter(deadline: .now() + 100) {
print(self.title) // self не может быть удалён
}
}
}
// ✅ ПРАВИЛЬНО: используй [weak self]
DispatchQueue.main.asyncAfter(deadline: .now() + 100) { [weak self] in
print(self?.title)
}
Практические советы
1. Prefer Stack over Heap
// ✅ ЛУЧШЕ: struct (обычно на Stack)
struct Point {
let x: Int
let y: Int
}
// ❌ ХУЖЕ: class (на Heap, ARC overhead)
class Point {
let x: Int
let y: Int
}
2. Избегай retain cycles
// ✅ ПРАВИЛЬНО
class ViewController: UIViewController {
var completionHandler: (() -> Void)?
func setup() {
completionHandler = { [weak self] in
self?.doSomething()
}
}
}
3. Профилируй память
// Xcode → Debug → Memory Graph
// Инструменты: Instruments → Allocations, Leaks
Вывод
Память в iOS разделена на:
- Stack — быстро, ограничено, автоматическое управление
- Heap — медленнее, большой размер, требует ARC
- Registers — самые быстрые, управляются компилятором
Rust правило: Move stack allocation by default, only use heap when needed. Swift следует этому с Value vs Reference Types.