В перле для любого произвольного массива @arr существует "специальная" переменная $#arr, содержащая индекс последнего элемента этого массива. Более того, мы можем изменить её значение, при этом изменится и сам массив, точнее - его длина.
опубликован: 2024-10-25 16:06
последняя редакция: 2024-10-25 16:07

Странности выделения памяти под массив

Здесь я продемонстрирую особенности выделения больших объёмов памяти под массив. Имеется ввиду присвоение различных значений переменно $#arr.
Как известно, в перле последний индекс элемента массива @arr можно получить из переменной $#arr, но верно и обратное - при присвоении целого значения этой переменной - массив изменится в соответствии с новым индексом. Если мы при этом массив "расширяем", то новым дополнительным элементам будут присвоены пустые строки. Это если вкратце.
Итак, что получится, если мы объявим массив с заведомо очень большим индексом последнего элемента? Пробуем
eval { $#arr = 1e16 };

Out of memory!

В целом, логично. Мы запросили слишком много памяти для своего массива, столько на моём компьютере нет. Любопытно, что eval в такой ситуации не перехватывает исключение, и программа просто вываливается.
Не было бы никаких вопросов, если бы перл вылетал и в строке
eval { $#arr = 1e20 };

Однако, этого не происходит! Справедливости ради, массив такого размера он не выделяет. И вероятно - даже не пытается выделить, поэтому программа и не вылетает:
eval { $#arr = 1e20 };
print $#arr, "\n";

-1

То есть, язык знает, что при некоторых, достаточно больших величинах индекса, даже не стоит пытаться отхватить столько памяти. Возникает вопрос - где проходит эта граница, после которой программа перестаёт аварийно завершаться?
Экспериментальным путём удалось выяснить, что граница проведена вблизи шестнадцатиричного значения
0x1FFFFFFFFFFFFFFF

или, другими словами, вблизи от
2305843009213693950

Это может означать, что перл выделяет под величину индекса массива не более 8 байт, что мы и попытались выяснить.