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


Perl允许预分配的数组。我们可以在使用前预先分配数组,然后我们可以添加更多元素。例如,分配50个阵列成员然后添加第51个成员,因为阵列是可扩展的。那么预分配数组会提高性能吗?


11645
2018-04-21 16:49


起源



答案:


这是因为计算机中的内存分配方式。计算机存储器就像白板上的空间:它具有与其他存储器相关的位置;它不能移动,必须复制。

如果您创建一个小数组,它可能如下所示:

@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版本,你的操作系统,你的硬件和你的性能容忍度。


13
2018-04-21 17:31