在perl中为数组预分配内存有什么用



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 越来越有可能不得不分配一大堆内存并复制所有内容。

还有另一个问题:内存碎片。如果您一遍又一遍地分配和重新分配,则大量内存可能会被切碎,因此很难找到大块的可用内存。这在现代操作系统上不是一个问题,但仍然是一个问题。它可能会使您看起来比实际拥有的内存少,并且可能导致操作系统将磁盘用作内存(虚拟内存)超过应有的内存。磁盘比内存慢。


我简化了很多事情。我让它看起来像Perl每次push时都必须重新分配。这不是真的。Perl 为数组分配的内存比它需要的要多。因此,您可以安全地向数组添加一些额外的条目,而无需 Perl 重新分配。字符串和哈希也是如此。

另一件事是,这可能是关于内存分配如何在现代操作系统上工作的过时观点......尽管 Perl 有时会在不信任操作系统的情况下进行自己的内存分配use Config; print $Config{usemymalloc}n表示Perl正在使用操作系统的内存分配,y表示它正在使用Perl的内存分配。

经验法则是:不要预先分配,这可能是浪费您的时间和计算机的内存。但是,如果以下所有条件都为真,请查看预分配是否有帮助。

  • 您分析并发现了问题。
  • 您正在通过添加数据结构来增量构建数据结构。
  • 您肯定知道其最小最终大小。
  • 这个尺寸是"大"的。

什么是"大"有待商榷,这取决于你的Perl版本,你的操作系统,你的硬件,以及你的性能容忍度。

最新更新