Память: стек, куча, объекты
Stack vs Heap
V8 использует два типа памяти:
Стек (Stack) — быстрая, структурированная память:
- Примитивы (
number,boolean,stringссылки) - Локальные переменные функций (если не захвачены замыканием)
- Адреса возврата, аргументы
Куча (Heap) — большая, неструктурированная память:
- Объекты, массивы, функции
- Строки (содержимое)
- Переменные, захваченные замыканиями (Context)
function example() {
let x = 42 // стек (примитив, не захвачен замыканием)
let obj = { a: 1 } // ссылка на стеке, объект в куче
let arr = [1, 2, 3] // ссылка на стеке, массив в куче
return x
}
Стек очищается автоматически при выходе из функции. Кучу очищает сборщик мусора (GC).
Hidden Classes (Maps)
JavaScript — динамический язык: свойства объекта можно добавлять и удалять на лету. Это должно быть медленно — каждый раз искать свойство по имени в хеш-таблице. Но V8 решает эту проблему через hidden classes (внутренне называются Maps).
Hidden class описывает форму (shape) объекта — какие свойства, в каком порядке, по каким смещениям:
const a = { x: 1, y: 2 }
const b = { x: 3, y: 4 }
// a и b разделяют один hidden class: { x: offset 0, y: offset 1 }
const c = { y: 1, x: 2 }
// c имеет ДРУГОЙ hidden class — порядок свойств отличается!
Когда V8 знает hidden class, доступ к свойству — это чтение по фиксированному смещению, как в C-структуре.
Shape Transitions
Добавление свойства создаёт transition — переход к новому hidden class:
const obj = {} // HiddenClass_0: {}
obj.x = 1 // HiddenClass_1: { x: offset 0 }
obj.y = 2 // HiddenClass_2: { x: offset 0, y: offset 1 }
V8 строит дерево переходов. Если два объекта проходят одинаковую последовательность добавлений, они получают один hidden class:
function createPoint(x, y) {
const p = {}
p.x = x // transition: HC_0 → HC_1
p.y = y // transition: HC_1 → HC_2
return p
}
const p1 = createPoint(1, 2) // HC_2
const p2 = createPoint(3, 4) // HC_2 — тот же hidden class!
Но если порядок добавления отличается:
const a = {}; a.x = 1; a.y = 2 // HC_A
const b = {}; b.y = 1; b.x = 2 // HC_B — другой hidden class!
Правило: инициализируй свойства объектов в одинаковом порядке.
Inline Caches (IC)
Inline cache — механизм ускорения повторного доступа к свойствам. При первом доступе к obj.x V8 ищет свойство по hidden class. При повторном — использует кэшированный результат.
Три состояния IC:
| Состояние | Описание | Скорость |
|---|---|---|
| Monomorphic | Все объекты имеют один hidden class | Максимальная |
| Polymorphic | 2-4 разных hidden class | Средняя |
| Megamorphic | 5+ hidden class | Минимальная (хеш-таблица) |
function getX(obj) { return obj.x }
// Мономорфный: все объекты одного shape
getX({ x: 1, y: 2 })
getX({ x: 3, y: 4 }) // быстро — IC hit
// Полиморфный: два разных shape
getX({ x: 1, y: 2 })
getX({ x: 1, z: 3 }) // медленнее — два варианта в IC
// Мегаморфный: много разных shapes
getX({ x: 1, a: 1 })
getX({ x: 1, b: 2 })
getX({ x: 1, c: 3 })
getX({ x: 1, d: 4 })
getX({ x: 1, e: 5 }) // IC переключился в megamorphic — медленный lookup
Правило: в горячих путях передавай объекты с одинаковой структурой.
Pointer Tagging и SMI Optimization
V8 использует pointer tagging — младший бит указателя кодирует тип:
- 0 (чётный) — указатель на объект в куче (HeapObject)
- 1 (нечётный) — SMI (Small Integer) — целое число, упакованное прямо в указатель
0x0000000A → указатель на объект (младший бит = 0)
0x0000000B → SMI со значением 5 (0xB >> 1 = 5, младший бит = 1)
SMI не требуют аллокации в куче — число хранится прямо в «указателе». Это экономит память и ускоряет арифметику для целых чисел в диапазоне от -2³⁰ до 2³⁰-1 (32-bit) или -2³¹ до 2³¹-1 (64-bit с pointer compression).
Числа за пределами SMI-диапазона и дробные числа хранятся как HeapNumber — отдельный объект в куче.
Итого
| Концепция | Описание |
|---|---|
| Stack | Примитивы, локальные переменные, адреса возврата — быстрая, автоматическая очистка |
| Heap | Объекты, массивы, замыкания — сборщик мусора |
| Hidden Classes | Описывают форму объекта, позволяют доступ к свойствам по смещению |
| Shape Transitions | Дерево переходов при добавлении свойств |
| Inline Caches | Кэш результатов поиска свойств: monomorphic → polymorphic → megamorphic |