【发布时间】:2016-08-15 00:40:10
【问题描述】:
Perl 允许预分配数组。我们可以在使用前预先分配数组,然后我们可以添加更多元素。例如,分配 50 个数组成员然后添加第 51 个成员,因为数组是可扩展的。那么预分配数组会提高性能吗?
【问题讨论】:
Perl 允许预分配数组。我们可以在使用前预先分配数组,然后我们可以添加更多元素。例如,分配 50 个数组成员然后添加第 51 个成员,因为数组是可扩展的。那么预分配数组会提高性能吗?
【问题讨论】:
这是因为计算机中内存的分配方式。计算机内存就像白板上的空间:它相对于其他内存有一个位置;不能移动,必须复制。
如果你创建一个小数组,它可能看起来像这样:
@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 不会费心擦除旧数据。它只会释放它,其他东西可以在需要时在它上面乱写。
这使得推送变得更加昂贵,尤其是对于需要复制更多数据的非常大的数组。随着您的数组变得越来越大,Perl 将不得不分配新的内存块并复制所有内容的可能性越来越大。
还有一个问题:内存碎片。如果您一遍又一遍地分配和重新分配,那么大块内存可能会被切碎,因此很难找到大块可用内存。这在现代操作系统上不是问题,但仍然是一个问题。它会使您的内存看起来比实际内存少,并且可能导致操作系统将磁盘用作内存(虚拟内存)的次数超出应有的程度。磁盘比内存慢。
我简化了很多事情。我让它看起来每次你push时Perl都必须重新分配。这不是真的。由于这个原因,Perl 为数组分配的内存比它需要的多。因此,您可以安全地向数组中添加一些额外的条目,而无需 Perl 重新分配。字符串和哈希也是如此。
另一件事是,对于现代操作系统上内存分配的工作原理,这可能是一个有点过时的观点……尽管如果 Perl 不信任操作系统,它有时会自己进行内存分配。检查use Config; print $Config{usemymalloc}。 n 表示 Perl 正在使用操作系统的内存分配,y 表示它正在使用 Perl。
经验法则是:不要预先分配,这可能会浪费您的时间和计算机的内存。但是,如果以下条件所有都为真,请查看预分配是否有帮助。
什么是“大”有待商榷,取决于您的 Perl 版本、操作系统、硬件和性能容差。
【讨论】: