Perl позволяет использовать предварительно распределенные массивы. Мы можем предварительно выделить массив перед использованием, тогда мы можем добавить еще несколько элементов. Например, выделение 50 элементов массива, а затем добавление 51-го элемента, поскольку массивы расширяемы. Таким образом, предварительное распределение массива повышает производительность?
Какая польза preallocating памяти для массива в perl?
Ответ 1
Из-за того, как память распределяется на компьютерах. Память компьютера подобна пространству на доске: она имеет положение относительно другой памяти; и он не может быть перемещен, он должен быть скопирован.
Если вы создадите небольшой массив, он может выглядеть так:
@array = (1, 4, 8, 12, 19);
allocate memory for @array
______________________| |______| a b c|__________
copy in the data
______________________| 1 4 8 12 19|______| a b c|__________
_
- нераспределенная память. |
указывает границы того, что выделяется вашему массиву. | a b c|
- это еще один массив.
Затем, если вы несколько раз нажмете на этот массив, Perl придется перераспределять память. В этом случае он может увеличить память, которую он уже имеет в нераспределенном пространстве.
push @array, 23, 42;
grow the existing memory
______________________| 1 4 8 12 19 | a b c|__________
add the new data
______________________| 1 4 8 12 19 23 42| a b c|__________
Теперь, что произойдет, если вы нажмете больше чисел на @array
? Он больше не может вырастить вашу память, есть еще один массив. Таким образом, как и на доске, он должен скопировать весь массив в ясный кусок памяти.
push @array, 85, 99;
Allocate a new chunk of memory
| | 1 4 8 12 19 23 42| a b c|__________
Copy the existing data
| 1 4 8 12 19 23 42 | 1 4 8 12 19 23 42| a b c|__________
Deallocate the old memory
| 1 4 8 12 19 23 42 |__1__4__8_12_19_23_42| a b c|__________
Add the new data
| 1 4 8 12 19 23 42 85 99|__1__4__8_12_19_23_42| a b c|__________
Чтобы сэкономить время, Perl не хочет стирать старые данные. Он просто освободит его, и что-то еще может нацарапать его, когда им нужно.
Это делает push более дорогим, особенно с очень большими массивами, которые должны копировать больше данных. По мере увеличения вашего массива все больше и больше вероятность, что Perl придется выделять свежий кусок памяти и копировать все.
Есть еще одна проблема: фрагментация памяти. Если вы распределяете и перераспределяете снова и снова, куски памяти могут быть нарезаны, поэтому трудно найти большие блоки свободной памяти. Это проблема не только для современных операционных систем, но и для беспокойства. Может показаться, что у вас меньше памяти, чем у вас на самом деле, и это может привести к тому, что операционная система будет использовать диск в качестве памяти (виртуальной памяти) больше, чем нужно. Диски медленнее памяти.
Я упростил многое. Я сделал вид, что Perl должен перераспределять каждый раз, когда вы push
. Это неверно. Perl выделяет больше памяти для массивов, чем нужно именно по этой причине. Таким образом, вы можете смело добавить несколько дополнительных записей в массив без перераспределения Perl. То же самое относится к строкам и хэшам.
Другое дело - это, вероятно, несколько устаревшее представление о том, как распределение памяти работает на современных операционных системах... хотя Perl иногда выполняет собственное распределение памяти, если не доверяет ОС. Проверьте use Config; print $Config{usemymalloc}
. n
указывает, что Perl использует выделение памяти операционной системы, y
указывает на использование Perl.
Эмпирическое правило: не предопределяйте, это, вероятно, пустая трата времени и памяти компьютера. Однако, если все приведенные ниже условия верны, посмотрите, помогает ли предварительное распределение.
- Вы профилировали и обнаружили проблему.
- Вы постепенно наращиваете структуру данных, добавляя к ней.
- Вы точно знаете минимальный возможный размер.
- Этот размер "большой".
Что такое "большой", для обсуждения и зависит от вашей версии Perl, вашей операционной системы, вашего оборудования и вашей производительности.