Ответ
В PHP массивы (тип array) — это упорядоченные хеш-таблицы, что определяет специфику работы с памятью:
-
Динамическое выделение с запасом (capacity): При добавлении элементов PHP выделяет память не поштучно, а блоками. Если массив превышает текущую вместимость, происходит дорогостоящая операция rehash — выделение нового, большего блока памяти и перераспределение всех существующих элементов.
$array = []; // Выделена начальная вместимость (например, на 8 элементов) for ($i = 0; $i < 100; $i++) { $array[$i] = $i; // PHP несколько раз увеличит вместимость (8 -> 16 -> 32 -> 64 -> 128) } -
Высокий overhead на элемент: Каждый элемент массива (
Bucket) хранит не только значение и ключ (хэш), но и ссылки для поддержки двусвязного списка (для сохранения порядка обхода). В PHP 8.x overhead составляет около 56 байт на элемент (плюс память на само значение и ключ). -
Память освобождается не сразу при
unset(): При удалении элемента PHP лишь помечаетBucketкак неиспользуемый (IS_UNDEF). Физическое освобождение памяти и сокращение размера массива может произойти только при следующем рехеше или при вызовеarray_values()(который создает новый массив).$arr = range(1, 1000); // ~56KB + данные unset($arr[500]); // Память не вернется системе, элемент помечен UNDEF $arr = array_values($arr); // Создается новый массив, старый удаляется GC -
Оптимизации:
SplFixedArray: Для массивов с целочисленными ключами, известными заранее, использует C-подобный массив, почти не имеющий overhead.- Предварительное выделение: Если известен примерный размер, можно задать его через
$array = new SplFixedArray(10000);или использоватьarray_fill(0, $size, null)для обычного массива, чтобы минимизировать рехеши. - Явная очистка: Для больших массивов лучший способ освободить память — присвоить переменной
nullили вызватьunset()на всей переменной.