Потребление памяти разреженных массивов в Node.js

Я написал небольшую программу, которая производит массивы, которая работает довольно долго (почти навсегда;-)):

var results = [];
var i = 1;

while (true) {
  console.log(i++);
  results.push([]);
}

Когда вместо пустого массива я создаю разреженный массив длины iпрограмма вылетает довольно быстро:

var results = [];
var i = 1;

while (true) {
  console.log(i);
  results.push(new Array(i++));
}

На самом деле я встаю до i равный 17424, то я получаю сообщение об ошибке, говорящее мне

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Abort trap: 6

и Node.js возвращает меня к консоли. Поскольку единственное отличие состоит в том, что второй создает "большие" пустые массивы, чем первые, это означает, что пустой разреженный массив длины n занимает n раз пространство пустого массива с длиной 1,

Прав ли я в этом (особенно в Node.js)?

Еще один вопрос: если я бегу

var results = [];
var i = 1;

while (true) {
  console.log(i);
  var temp = [];
  temp[i++] = i;
  results.push(temp);
}

тогда я получаю до 1286175, затем он снова вылетает с:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Abort trap: 6

Почему это ведет себя не так, как другие два варианта?

PS: я использую Node.js 0.12.0 для запуска этого на OS X.

2 ответа

Решение

Когда вы объявляете массив с размером

Array(1024);

Вы делаете так, чтобы он выделил место для 1024 элементов. Он должен выделять это пространство заранее, потому что эта форма объявления массива является оптимизационным

"Мне нужно, чтобы вы зарезервировали 1024 местоположения, чтобы вы не меняли размер массива постоянно, поскольку я добавляю в него больше элементов".

Как вы, вероятно, знаете, объявление массива просто [] по-прежнему позволяет помещать на него неограниченное количество элементов, однако размер массива медленно изменяется (скорее всего, memcpy()негласно разрешить такое поведение.

РЕДАКТИРОВАТЬ:

Причина, по которой вы получаете намного более высокие итерации во втором примере, заключается в том, что вы сейчас используете разреженный массив. С разреженным массивом делает

var arr = []
arr[1000000] = 1;

Не означает, что ваш массив теперь использует 1 000 000 записей в памяти. Сравните это с плотным массивом

var arr = Array(1000000);

Который явно указывает среде выполнения зарезервировать массив, который может хранить 1000000 записей в памяти.

Связанный вопрос Stackru: /questions/9797033/yavlyayutsya-li-massivyi-javascript-redkimi/9797041#9797041

V8, движок JS в Node, использует 4 байта для каждого элемента в, казалось бы, пустом массиве. Лучший способ узнать это наверняка - создать пустые массивы в Chrome и использовать профилировщик, чтобы увидеть, какой дополнительный размер использовал массив. См. https://developer.chrome.com/devtools/docs/heap-profiling для получения подробной информации о том, как вы можете сделать это...

Другие вопросы по тегам