PHP. Как увеличить потребление памяти в 3 и более раз при работе с массивами
Содержание
Общие сведения.
Увеличиваем потребление памяти вдвое.
Увеличиваем потребление памяти втрое.
Ещё раз увеличиваем потребление памяти на ровном месте.
Заключение.
Общие сведения
Известно, что PHP активно использует механизм copy-on-write. Это означает, что при попытке внутри функции что-то записать в переданные ей параметры, вначале будет сделана копия этой переменной, а уж затем в неё что-то запишется. Такая же ситуация наблюдается с итерацией массива с помощью foreach. Отсюда следует, что вам потребуется увеличить количество памяти для создания копии переменной и времени (ресурсов ЦП), чтобы всё это проделать. Т.е. возникнет пауза, прежде чем PHP перейдёт к следующей строчке вашей программы.
Но прежде чем продолжить дальше по теме, я бы хотел рассказать зачем вообще, что-то передаётся по ссылке, а что-то - по значению. Честно, говоря, я об этом узнал несколько месяцев назад. Т.е. то, что объекты (и массивы, об этом - далее) в PHP всегда передаются по ссылке, а всё остальное по значению - я знал. Но вот зачем - нет. Ответ нашёлся в курсе по Go, как ни странно. Это компромисс. Если умолчать про массивы (и, как заметили в комментариях, строки, которые тоже массивы), то все остальные типы данных в PHP - это скаляры (чтобы быть точным см. is_scalar). Скаляры не занимают много памяти, поэтому их можно быстро скопировать, и передать в функцию копию хранимого значения. При этом на вызывающей стороне значение переменной не изменится. Объекты же могут быть огромными, например DOM-дерево огромного XML-документа. Делать копию такого объекта слишком дорого и по времени и по памяти, поэтому он передаётся по ссылке. Так почему бы не передавать скаляры тоже по ссылке? Дело в том, что передавая что-либо по ссылке мы таким образом теряем контроль над переменными в месте вызова. Представьте себе функцию с кучей параметров:
function doSmth($x1, $y2, $scale, $pojection, $alpha, $type, $reference, $mode): float;
И все они передаются по ссылке. Что случится с локальным контекстом после вызова этой функции? Останутся ли все эти переменные в тех же значениях, что и были до вызова doSmth
? Неведомо сие. Всё это остаётся на совести разработчика функции doSmth
. Т.о. вы частично или полностью теряете контроль над своей программой. Поэтому и придумали компромисс: скаляры всегда передаём по значению, а объекты - по ссылке.
Уточнение, которое, кажется, необходимым сделать, судя по комментариям. В «Основы подсчёта ссылок» есть следующий текст:
Так как PHP содержит пользовательские ссылки, которые можно создать оператором &, контейнер zval также содержит внутренний механизм подсчёта ссылок для оптимизации использования памяти..
Это означает, что в PHP есть как ссылки, которые определяет пользователь через амперсанд, так и внутренние ссылки, которые PHP использует где-то там в своих недрах и для своих нужд. Когда в статье говорится о ссылках и передаче по ссылке, то имеется в виду такое поведение, когда копия значения переменной не создаётся.
Однако в документации есть строгое определение того, что PHP называет ссылкой и как с этим работать, см. тут, тут и «References Explained». В рамках этой статьи я этому строгому определению не следую.
Увеличиваем потребление памяти вдвое
Массивы в PHP передаются по ссылке. Но если вы что-то попытаетесь записать в него, то будет создана копия массива со всеми вытекающими по памяти и процессору. Это и есть реализация механизма copy-on-write. Пример:
<?php
function doSmth(array $array, int $memory) {
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
$array[0] = 0;
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
}
$memory = memory_get_usage();
$array = range(1, 100);
doSmth($array, $memory);
На моем компе с PHP 8.2.3, кстати, вывод будет таким:
memory: 2616
memory: 5264
Т.е. всего лишь записав нолик в первый элемент массива, мы увеличили потребление памяти вдвое! Это ли не чудо! Array assignment always involves value copying. Use the reference operator to copy an array by reference, см. тут. Что делать с этим? Да, нужно поставить амперсанд перед параметром $array
, вот так: function doSmth(array &$array, int $memory)
. Тогда вывод станет таким:
memory: 2648
memory: 2680
2680 - 2648 = 32. 32 - это скорее всего кол-во памяти, выделенное на саму переменную $array
(но не её значение). Как бы там ни было, это не вдвое. Проблема решена. Сейчас расскажу, как увеличить потребление памяти втрое (да, сам понимаю, что немного странно написана статья: казалось бы нужно рассказывать, как уменьшить потребление памяти, но... так показалось проще объяснить).
Увеличиваем потребление памяти втрое
Затираем амперсанд, возвращаем всё взад и попробуем сделать что-нибудь с массивом, например увеличить на 1 каждый его элемент (всё то же самое, только добавили foreach
и break
, чтобы не мотать весь массив):
<?php
function doSmth(array $array, int $memory) {
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
$array[0] = 0;
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
foreach ($array as $i => $value) {
$array[$i] ++;
printf('memory: %s, i: %s%s', memory_get_usage() - $memory, $i, PHP_EOL);
break;
}
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
}
$memory = memory_get_usage();
$array = range(1, 100);
doSmth($array, $memory);
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
Вывод:
memory: 2616
memory: 5264
memory: 7880, i: 0
memory: 5264
memory: 2648
Как видите, потребляемая память максимальна внутри цикла. Дело в том, что при попытке что-то записать в массив внутри цикла foreach
, PHP создаёт (в нашем случае ещё одну) копию массива. И даже если поставить амперсанд перед $value
, то это не поможет никак.
Полный вывод работы скрипта без break и с амперсандом перед $value
<?php
function doSmth(array $array, int $memory) {
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
$array[0] = 0;
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
foreach ($array as $i => &$value) {
// $array[$i] ++;
$value ++;
printf('memory: %s, i: %s%s', memory_get_usage() - $memory, $i, PHP_EOL);
// break;
}
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
}
$memory = memory_get_usage();
$array = range(0, 99);
doSmth($array, $memory);
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
memory: 2616
memory: 5264
memory: 5328, i: 0
memory: 5360, i: 1
memory: 5392, i: 2
memory: 5424, i: 3
memory: 5456, i: 4
memory: 5488, i: 5
memory: 5520, i: 6
memory: 5552, i: 7
memory: 5584, i: 8
memory: 5616, i: 9
memory: 5648, i: 10
memory: 5680, i: 11
memory: 5712, i: 12
memory: 5744, i: 13
memory: 5776, i: 14
memory: 5808, i: 15
memory: 5840, i: 16
memory: 5872, i: 17
memory: 5904, i: 18
memory: 5936, i: 19
memory: 5968, i: 20
memory: 6000, i: 21
memory: 6032, i: 22
memory: 6064, i: 23
memory: 6096, i: 24
memory: 6128, i: 25
memory: 6160, i: 26
memory: 6192, i: 27
memory: 6224, i: 28
memory: 6256, i: 29
memory: 6288, i: 30
memory: 6320, i: 31
memory: 6352, i: 32
memory: 6384, i: 33
memory: 6416, i: 34
memory: 6448, i: 35
memory: 6480, i: 36
memory: 6512, i: 37
memory: 6544, i: 38
memory: 6576, i: 39
memory: 6608, i: 40
memory: 6640, i: 41
memory: 6672, i: 42
memory: 6704, i: 43
memory: 6736, i: 44
memory: 6768, i: 45
memory: 6800, i: 46
memory: 6832, i: 47
memory: 6864, i: 48
memory: 6896, i: 49
memory: 6928, i: 50
memory: 6960, i: 51
memory: 6992, i: 52
memory: 7024, i: 53
memory: 7056, i: 54
memory: 7088, i: 55
memory: 7120, i: 56
memory: 7152, i: 57
memory: 7184, i: 58
memory: 7216, i: 59
memory: 7248, i: 60
memory: 7280, i: 61
memory: 7312, i: 62
memory: 7344, i: 63
memory: 7376, i: 64
memory: 7408, i: 65
memory: 7440, i: 66
memory: 7472, i: 67
memory: 7504, i: 68
memory: 7536, i: 69
memory: 7568, i: 70
memory: 7600, i: 71
memory: 7632, i: 72
memory: 7664, i: 73
memory: 7696, i: 74
memory: 7728, i: 75
memory: 7760, i: 76
memory: 7792, i: 77
memory: 7824, i: 78
memory: 7856, i: 79
memory: 7888, i: 80
memory: 7920, i: 81
memory: 7952, i: 82
memory: 7984, i: 83
memory: 8016, i: 84
memory: 8048, i: 85
memory: 8080, i: 86
memory: 8112, i: 87
memory: 8144, i: 88
memory: 8176, i: 89
memory: 8208, i: 90
memory: 8240, i: 91
memory: 8272, i: 92
memory: 8304, i: 93
memory: 8336, i: 94
memory: 8368, i: 95
memory: 8400, i: 96
memory: 8432, i: 97
memory: 8464, i: 98
memory: 8496, i: 99
memory: 8496
memory: 2648
foreach
вообще достаточно проблемная конструкция для синтаксического сахара. Без проблем её можно использовать только для "посмотреть" на каждой итерации, "сделать" же что-то обходится слишком дорого:
Альтернативой будет использование цикла for
.
Hidden text
<?php
function doSmth(array $array, int $memory) {
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
$array[0] = 0;
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
$count = count($array);
for ($i = 0; $i < $count; $i ++) {
$array[$i] = 100;
printf('memory: %s, i: %s%s', memory_get_usage() - $memory, $i, PHP_EOL);
}
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
}
$memory = memory_get_usage();
$array = range(0, 99);
doSmth($array, $memory);
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
memory: 2616
memory: 5264
memory: 5264, i: 0
memory: 5264, i: 1
memory: 5264, i: 2
memory: 5264, i: 3
memory: 5264, i: 4
memory: 5264, i: 5
memory: 5264, i: 6
memory: 5264, i: 7
memory: 5264, i: 8
memory: 5264, i: 9
memory: 5264, i: 10
memory: 5264, i: 11
memory: 5264, i: 12
memory: 5264, i: 13
memory: 5264, i: 14
memory: 5264, i: 15
memory: 5264, i: 16
memory: 5264, i: 17
memory: 5264, i: 18
memory: 5264, i: 19
memory: 5264, i: 20
memory: 5264, i: 21
memory: 5264, i: 22
memory: 5264, i: 23
memory: 5264, i: 24
memory: 5264, i: 25
memory: 5264, i: 26
memory: 5264, i: 27
memory: 5264, i: 28
memory: 5264, i: 29
memory: 5264, i: 30
memory: 5264, i: 31
memory: 5264, i: 32
memory: 5264, i: 33
memory: 5264, i: 34
memory: 5264, i: 35
memory: 5264, i: 36
memory: 5264, i: 37
memory: 5264, i: 38
memory: 5264, i: 39
memory: 5264, i: 40
memory: 5264, i: 41
memory: 5264, i: 42
memory: 5264, i: 43
memory: 5264, i: 44
memory: 5264, i: 45
memory: 5264, i: 46
memory: 5264, i: 47
memory: 5264, i: 48
memory: 5264, i: 49
memory: 5264, i: 50
memory: 5264, i: 51
memory: 5264, i: 52
memory: 5264, i: 53
memory: 5264, i: 54
memory: 5264, i: 55
memory: 5264, i: 56
memory: 5264, i: 57
memory: 5264, i: 58
memory: 5264, i: 59
memory: 5264, i: 60
memory: 5264, i: 61
memory: 5264, i: 62
memory: 5264, i: 63
memory: 5264, i: 64
memory: 5264, i: 65
memory: 5264, i: 66
memory: 5264, i: 67
memory: 5264, i: 68
memory: 5264, i: 69
memory: 5264, i: 70
memory: 5264, i: 71
memory: 5264, i: 72
memory: 5264, i: 73
memory: 5264, i: 74
memory: 5264, i: 75
memory: 5264, i: 76
memory: 5264, i: 77
memory: 5264, i: 78
memory: 5264, i: 79
memory: 5264, i: 80
memory: 5264, i: 81
memory: 5264, i: 82
memory: 5264, i: 83
memory: 5264, i: 84
memory: 5264, i: 85
memory: 5264, i: 86
memory: 5264, i: 87
memory: 5264, i: 88
memory: 5264, i: 89
memory: 5264, i: 90
memory: 5264, i: 91
memory: 5264, i: 92
memory: 5264, i: 93
memory: 5264, i: 94
memory: 5264, i: 95
memory: 5264, i: 96
memory: 5264, i: 97
memory: 5264, i: 98
memory: 5264, i: 99
memory: 5264
memory: 2648
Обратите внимание, что размер массива должен вычисляться только один раз перед циклом, а не на каждой итерации:
for ($i = 0; $i < count($array); $i ++)
По ходу пьесы обнаружил ещё две интересные статьи на Хабре:
Сравнение производительности перебора массивов в цикле через for() и foreach(). Так ли это для 8-ой версии не знаю, не проверял.
array_* vs foreach или PHP7 vs PHP5. Тест на скорую руку показал, что
array_map
потребляет тоже почти в 3 раза больше памяти (а без амперсанда перед$array
ещё больше).
Использование array_map
<?php
function doSmth(array &$array, int $memory) {
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
$array[0] = 0;
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
// foreach ($array as $i => &$value) {
// // $array[$i] ++;
// $value ++;
// printf('memory: %s, i: %s%s', memory_get_usage() - $memory, $i, PHP_EOL);
// // break;
// }
// $count = count($array);
// for ($i = 0; $i < $count; $i ++) {
// $array[$i] = 100;
// printf('memory: %s, i: %s%s', memory_get_usage() - $memory, $i, PHP_EOL);
// }
array_map(function($value) use ($memory) {
$value ++;
printf('memory: %s, i: %s%s', memory_get_usage() - $memory, $value, PHP_EOL);
}, $array);
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
}
$memory = memory_get_usage();
$array = range(0, 99);
doSmth($array, $memory);
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
memory: 2648
memory: 2680
memory: 6160, i: 1
memory: 6160, i: 2
memory: 6160, i: 3
memory: 6160, i: 4
memory: 6160, i: 5
memory: 6160, i: 6
memory: 6160, i: 7
memory: 6160, i: 8
memory: 6160, i: 9
memory: 6160, i: 10
memory: 6160, i: 11
memory: 6160, i: 12
memory: 6160, i: 13
memory: 6160, i: 14
memory: 6160, i: 15
memory: 6160, i: 16
memory: 6160, i: 17
memory: 6160, i: 18
memory: 6160, i: 19
memory: 6160, i: 20
memory: 6160, i: 21
memory: 6160, i: 22
memory: 6160, i: 23
memory: 6160, i: 24
memory: 6160, i: 25
memory: 6160, i: 26
memory: 6160, i: 27
memory: 6160, i: 28
memory: 6160, i: 29
memory: 6160, i: 30
memory: 6160, i: 31
memory: 6160, i: 32
memory: 6160, i: 33
memory: 6160, i: 34
memory: 6160, i: 35
memory: 6160, i: 36
memory: 6160, i: 37
memory: 6160, i: 38
memory: 6160, i: 39
memory: 6160, i: 40
memory: 6160, i: 41
memory: 6160, i: 42
memory: 6160, i: 43
memory: 6160, i: 44
memory: 6160, i: 45
memory: 6160, i: 46
memory: 6160, i: 47
memory: 6160, i: 48
memory: 6160, i: 49
memory: 6160, i: 50
memory: 6160, i: 51
memory: 6160, i: 52
memory: 6160, i: 53
memory: 6160, i: 54
memory: 6160, i: 55
memory: 6160, i: 56
memory: 6160, i: 57
memory: 6160, i: 58
memory: 6160, i: 59
memory: 6160, i: 60
memory: 6160, i: 61
memory: 6160, i: 62
memory: 6160, i: 63
memory: 6160, i: 64
memory: 6160, i: 65
memory: 6160, i: 66
memory: 6160, i: 67
memory: 6160, i: 68
memory: 6160, i: 69
memory: 6160, i: 70
memory: 6160, i: 71
memory: 6160, i: 72
memory: 6160, i: 73
memory: 6160, i: 74
memory: 6160, i: 75
memory: 6160, i: 76
memory: 6160, i: 77
memory: 6160, i: 78
memory: 6160, i: 79
memory: 6160, i: 80
memory: 6160, i: 81
memory: 6160, i: 82
memory: 6160, i: 83
memory: 6160, i: 84
memory: 6160, i: 85
memory: 6160, i: 86
memory: 6160, i: 87
memory: 6160, i: 88
memory: 6160, i: 89
memory: 6160, i: 90
memory: 6160, i: 91
memory: 6160, i: 92
memory: 6160, i: 93
memory: 6160, i: 94
memory: 6160, i: 95
memory: 6160, i: 96
memory: 6160, i: 97
memory: 6160, i: 98
memory: 6160, i: 99
memory: 6160, i: 100
memory: 2680
memory: 2680
Таким образом, оптимальным, без всяких дополнительных затрат, будет вариант с передачей массива по ссылке и использованием for
.
Пример
<?php
function doSmth(array &$array, int $memory) {
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
$array[0] = 0;
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
$count = count($array);
for ($i = 0; $i < $count; $i ++) {
$array[$i] = 100;
printf('memory: %s, i: %s%s', memory_get_usage() - $memory, $i, PHP_EOL);
}
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
}
$memory = memory_get_usage();
$array = range(0, 99);
doSmth($array, $memory);
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
memory: 2648
memory: 2680
memory: 2680, i: 0
memory: 2680, i: 1
memory: 2680, i: 2
memory: 2680, i: 3
memory: 2680, i: 4
memory: 2680, i: 5
memory: 2680, i: 6
memory: 2680, i: 7
memory: 2680, i: 8
memory: 2680, i: 9
memory: 2680, i: 10
memory: 2680, i: 11
memory: 2680, i: 12
memory: 2680, i: 13
memory: 2680, i: 14
memory: 2680, i: 15
memory: 2680, i: 16
memory: 2680, i: 17
memory: 2680, i: 18
memory: 2680, i: 19
memory: 2680, i: 20
memory: 2680, i: 21
memory: 2680, i: 22
memory: 2680, i: 23
memory: 2680, i: 24
memory: 2680, i: 25
memory: 2680, i: 26
memory: 2680, i: 27
memory: 2680, i: 28
memory: 2680, i: 29
memory: 2680, i: 30
memory: 2680, i: 31
memory: 2680, i: 32
memory: 2680, i: 33
memory: 2680, i: 34
memory: 2680, i: 35
memory: 2680, i: 36
memory: 2680, i: 37
memory: 2680, i: 38
memory: 2680, i: 39
memory: 2680, i: 40
memory: 2680, i: 41
memory: 2680, i: 42
memory: 2680, i: 43
memory: 2680, i: 44
memory: 2680, i: 45
memory: 2680, i: 46
memory: 2680, i: 47
memory: 2680, i: 48
memory: 2680, i: 49
memory: 2680, i: 50
memory: 2680, i: 51
memory: 2680, i: 52
memory: 2680, i: 53
memory: 2680, i: 54
memory: 2680, i: 55
memory: 2680, i: 56
memory: 2680, i: 57
memory: 2680, i: 58
memory: 2680, i: 59
memory: 2680, i: 60
memory: 2680, i: 61
memory: 2680, i: 62
memory: 2680, i: 63
memory: 2680, i: 64
memory: 2680, i: 65
memory: 2680, i: 66
memory: 2680, i: 67
memory: 2680, i: 68
memory: 2680, i: 69
memory: 2680, i: 70
memory: 2680, i: 71
memory: 2680, i: 72
memory: 2680, i: 73
memory: 2680, i: 74
memory: 2680, i: 75
memory: 2680, i: 76
memory: 2680, i: 77
memory: 2680, i: 78
memory: 2680, i: 79
memory: 2680, i: 80
memory: 2680, i: 81
memory: 2680, i: 82
memory: 2680, i: 83
memory: 2680, i: 84
memory: 2680, i: 85
memory: 2680, i: 86
memory: 2680, i: 87
memory: 2680, i: 88
memory: 2680, i: 89
memory: 2680, i: 90
memory: 2680, i: 91
memory: 2680, i: 92
memory: 2680, i: 93
memory: 2680, i: 94
memory: 2680, i: 95
memory: 2680, i: 96
memory: 2680, i: 97
memory: 2680, i: 98
memory: 2680, i: 99
memory: 2680
memory: 2680
Ещё раз увеличиваем потребление памяти на ровном месте
Ну и сладкое на десерт. В замечательной статье «Массивы в РНР 7: хэш-таблицы» говорится о том, что массив, точнее его внутреннее представление может храниться в упакованном и классическом виде. В упакованном - значит в сжатом. Сжатым массив создаётся, когда в нем используются только целочисленные ключи и только по порядку, например так:
<?php
$array = [];
$array[] = 'Один';
$array[] = 'Два';
...
Или используя функцию range
, как это делалось в коде выше, например:
<?php
$memory = memory_get_usage();
$array = range(0, 99);
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
$array['qwe'] = 'new item value';
printf('memory: %s%s', memory_get_usage() - $memory, PHP_EOL);
Вывод:
memory: 2616
memory: 8280
Массив начал занимать в 3 раза больше памяти после того, как в него добавили один (один!) элемент. В 3 раза, Карл! На ровном месте. Никто не ждал подвоха, а тут опять и снова!
Для других значений (вместо 100) статистика по увеличению потребления памяти выглядит так:
Размер массива, шт | Кол-во памяти до, байт | Кол-во памяти после, байт | Разница, раз |
10 | 408 | 728 | 1.8 |
100 | 2648 | 8280 | 3.1 |
1000 | 20568 | 41048 | 2 |
10000 | 266328 | 655448 | 2.5 |
100000 | 2101360 | 5242992 | 2.5 |
1000000 | 16781424 | 41943152 | 2.5 |
Таким образом, если вдруг вам захочется добавить в ваш массив какую-то информацию об этом же массиве (например среднее значение или min и max), то не надо. Создайте для этого другой массив или используйте stdClass:
<?php
$bigArray = range(0, 10000000);
$info = new stdClass; // $info = []
$info->data = $bigArray; // $info['data'] = $bigArray;
$info->min = min($bigArray); // $info['min'] = min($bigArray);
$info->max = ...; // $info['max'] = ...;
...
Справедливости ради отмечу, что утверждение о том, что целочисленные ключи должны идти строго по порядку - не совсем верно. Они могут идти не по порядку до тех пор, пока значение ключа не превысит размер хэш-таблицы, см. раздел «Конструкция хэш-таблицы».
Заключение
Аккуратно работайте с массивами, особенно с большими. Их точно лучше передавать по ссылке, как PHP передаёт объекты. Используйте for
. Думайте, проверяйте и замеряйте. Держите массивы упакованными. Рассмотрите возможность использования SplFixedArray.
Тут вообще нужно быть осторожным и проверять всё именно для вашей версии PHP. Работает ли for
быстрее foreach
на восьмёрке? А на семёрке? А на пятёрке? Т.е. всё то, что написано, верно для моей версии PHP на моём компьютере, но верно ли для вас - вопрос.
P. S.
Обнаружил ещё одну интересную статью: «Насколько большие массивы (и значения) в PHP? (Подсказка: ОЧЕНЬ БОЛЬШИЕ)».
В комментариях, у пользователя @inilim2 показатели потребления памяти оказались в 3 раза выше, чем у меня. Выяснилось, что с версии 8.2 PHP стал потреблять гораздо меньше памяти (по крайней мере для хранения целочисленных массивов).
@FanatPHP подсказал инструмент для тестирования кода PHP на разных версиях одновременно. Итого:
сколько памяти PHP потребляет на массив из 100 элементов: https://3v4l.org/RK5sK (тут в байтах).
сколько памяти PHP потребляет на массив из 100000 элементов: https://3v4l.org/c377f (тут в мегабайтах).