Есть ли внутренние механизмы выделения памяти при добавлении элементов в массив в JavaScript
Что проверяют
Понимаете ли вы, что спецификация ECMAScript про память ничего не говорит, всё происходит внутри движка, и знаете ли, как это устроено хотя бы в V8. Интервьюер ведёт к производительности: почему одни массивы быстрые, а другие нет. Следом часто спрашивают, что лучше, push в пустой массив или new Array(n).
Как отвечать
Да, механизмы есть, и они похожи на динамический массив из классических структур данных. На примере V8:
- хранилище элементов: элементы лежат в отдельном буфере с запасом ёмкости. Пока место есть,
pushпросто пишет в следующую ячейку; - рост: когда ёмкость кончилась, V8 выделяет буфер примерно в полтора раза больше плюс небольшой запас и копирует туда элементы. Старый буфер освобождает сборщик мусора, не мгновенно. Поэтому
pushв среднем стоит O(1), хотя отдельные вызовы дороже; - виды элементов: V8 помнит, что лежит в массиве. Только малые целые, только дробные числа (они хранятся без упаковки) или произвольные значения, и отдельно отмечается, есть ли дыры. Переход идёт в одну сторону: положили в массив целых строку или сделали дыру, и быстрый вид не вернётся;
- словарный режим: запишите
arr[1000000] = 1в пустой массив, и движок не станет выделять миллион ячеек, а переведёт элементы в хэш-таблицу. Доступ по индексу тогда заметно медленнее.
Если нужен настоящий непрерывный кусок памяти одного типа, для этого есть TypedArray поверх ArrayBuffer. Его размер фиксирован, а буфер с возможностью роста создаётся с опцией maxByteLength.
Где спотыкаются
Говорят, что массив в JS хранится непрерывно, как в C. Это верно лишь для быстрых видов элементов, и даже там для объектов в ячейках лежат ссылки, а сами объекты разбросаны по куче.
Считают new Array(n) бесспорной оптимизацией. Память под элементы действительно выделяется сразу, но массив помечается как дырявый, и в горячем коде это может съесть выигрыш.
Портят массивы по мелочи: delete arr[i] вместо splice, смесь чисел и строк, запись далеко за концом. Каждое такое действие переводит массив в более медленный вид.