Delphi动态数组效率

时间:2017-07-05 13:07:24

标签: delphi

我不是Delphi专家,我在网上阅读有关动态数组和静态数组的内容。在this文章中,我找到了一个名为“Dynamic v.Static Arrays”的章节,其中包含一个代码段,作者在下面说:

  

[...]访问动态数组可能比静态数组更快!

我已经理解动态数组位于堆上(它们是用引用/指针实现的)。

到目前为止,我知道动态数组的访问时间更长。但这与分配是一回事吗?就像我打电话SetLength(MyDynArray, 5)的速度慢于创建MyArray = array[0..4] of XXX

1 个答案:

答案 0 :(得分:13)

  

到目前为止,我知道动态数组的访问时间更长。

这是不正确的。该文中的陈述完全是错误的。

  

但这与分配相同吗?就像我打电话SetLength(MyDynArray, 5)的速度慢于创建MyArray = array[0..4] of XXX

一个常见的谬论是静态数组在堆上分配。它们可以是全局变量,因此在加载模块时会自动分配。它们可以是局部变量并在堆栈上分配。可以通过调用NewGetMem动态分配它们。或者它们可以包含在复合类型(例如记录或类)中,因此以任何方式分配拥有对象。

说清楚之后,让我们考虑一些常见的情况。

局部变量,静态数组类型

如上所述,声明为局部变量的静态数组在堆栈上分配。分配是自动的,基本上是免费的。将分配视为由编译器执行(当它生成用于保留堆栈帧的代码时)。因此,分配没有运行时成本。可能存在访问运行时成本,因为这可能会生成页面错误。这完全正常,如果你想使用一个小的固定大小的数组作为局部变量,那么没有更快的方法。

类的成员变量,静态数组类型

同样,如上所述,分配由包含对象执行。静态数组是为对象保留的空间的一部分,当实例化对象时,在堆上分配了足够的内存。堆分配的成本通常不会很大程度上取决于要分配的块的大小。该语句的一个例外可能是非常大的块,但我假设你的数组大小相当小,数十或数百个字节。有了这些知识,我们再次看到分配的成本基本上为零,因为我们已经为包含对象分配了内存。

局部变量,动态数组类型

动态数组由指针表示。所以你的局部变量是在堆栈上分配的指针。相同的参数适用于任何其他局部变量,例如上面讨论的静态数组类型的局部变量。分配基本上是免费的。在您对此变量执行任何操作之前,您需要通过调用SetLength来分配它。这导致堆分配,这是昂贵的。同样,当你完成后,你必须解除分配。

类的成员变量,动态数组类型

同样,动态数组指针的分配是免费的,但您必须调用SetLength来分配。这是一个堆分配。当对象被破坏时,也需要重新分配。

<强>结论

对于编译时已知长度的小数组,使用静态数组可以更有效地分配和释放。

请注意,我只考虑在此分配。如果分配是使用对象所花费时间的相对不重要的部分,那么这种性能特征可能无关紧要。例如,假设在程序启动时分配数组,然后在程序的持续时间内重复使用。在这种情况下,访问时间主导了分配时间,分配时间之间的差异变得无关紧要。

另一方面,想象一下在程序生命周期中重复调用的一个简短函数,让我们假设这个函数是性能瓶颈。如果它在小型阵列上运行,则使用动态阵列的分配成本可能很大。

你很少能用性能来制定严格的规则。您需要了解这些工具的工作原理,并了解您的程序如何使用这些工具。然后,您可以形成关于哪种编码策略可能表现最佳的意见,然后您应该通过分析来测试这些意见。你会比你预期的直觉不是一个很好的预测性能会让你感到惊讶。