Array SMI vs Double
V8 хранит массивы в специализированных режимах elements: PACKED_SMI, PACKED_DOUBLE, PACKED_ELEMENTS, плюс HOLEY-варианты. Переход между ними — деоптимизация массива.
Иерархия типов elements
PACKED_SMI_ELEMENTS (только SMI, без дыр)
↓
PACKED_DOUBLE_ELEMENTS (целые + float, без дыр)
↓
PACKED_ELEMENTS (любые объекты, без дыр)
↓
HOLEY_* (с дырами — медленнее)
↓
DICTIONARY_ELEMENTS (hashmap)
Переход только вниз. Назад дороги нет.
Что вызывает переход
const a = [1, 2, 3]; // PACKED_SMI
a.push(1.5); // → PACKED_DOUBLE
a.push('x'); // → PACKED_ELEMENTS
a[100] = 1; // → HOLEY (дыра)
delete a[5]; // → HOLEY
new Array(1000); // ← сразу HOLEY!
Парадокс double быстрее SMI
В одном Node-бенчмарке массив double обогнал массив SMI (~0.95 vs ~1.4с). Причина — аллокация через push в Node реаллоцирует buffer хуже для SMI.
В чистом V8 (d8) и Chrome — SMI снова в 2 раза быстрее double.
«В Chrome float-массив в 2 раза МЕДЛЕННЕЕ SMI. В Node float-массив реально быстрее SMI (~0.95 vs ~1.4с).» «Float физически не может обгонять SMI на чистой математике.»
Подводные камни
new Array(n)создаёт holey массив сразу — медленный.- Лучше
Array.from({length: n}, ...)или заранееfill(0). - Один
null/undefinedв массиве чисел → переход в PACKED_ELEMENTS. - Удаление через
delete arr[i]создаёт дыру. Лучшеsplice.
Источники
- Разбор вопроса о Array Double vs Array SMI · AsForJS · 2023-06-23
- Бенчмарк: Chrome float 2x медленнее SMI; Node наоборот (~0.95 vs ~1.4с)
- Производительность JavaScript Array в V8 (perf5) · AsForJS · 2024-04-06
- How to get maximum performance when working with JavaScript arrays · AsForJS · 2021-11-29
- Тесты Array Allocation · AsForJS · 2025-07-29