【问题标题】:Which scenario is lighter/heavier on heap allocations?哪种情况在堆分配上更轻/更重?
【发布时间】:2015-11-13 11:07:57
【问题描述】:

作为a previous answer to another question 的后续行动,我开始好奇堆分配是如何在循环中工作的。

以以下两种情况为例:

声明:

SomeList: TObjectList<TSomething>;

场景 1:

begin
  for X := 1 to 10 do
    SomeList[X].DoSomething;
end;

场景 2:

var
  S: TSomething;
begin
  for X:= 1 to 10 do begin
    S:= SomeList[X];
    S.DoSomething;
  end;
end;

现在我很好奇的是堆分配在这两种情况下是如何工作的。场景 1 在每次循环迭代中直接调用列表项,我想知道它是否会在每次循环迭代时添加到堆中并释放。另一方面,第二种情况显然有一个堆分配,只需声明一个局部变量。

我想知道的是哪种方案在堆分配上执行的负载较重(这是导致性能问题的主要原因之一)?

【问题讨论】:

  • 它们都不分配任何内存,因此从内存的角度来看,两者都不是更有效的(除了在场景 2 中分配指针变量,这是不相关的,编译器可能会优化掉)。唯一的区别是:哪个更容易输入和理解以进行维护?
  • 我理解的方式是,我声明了一个局部变量这一事实添加到堆中,以及在每次循环迭代时获取列表项。这种理解显然是错误的。
  • 本地(对象指针)变量根本不在堆上分配。它是一个局部变量,准确分配了SizeOf(Pointer) 字节的堆栈空间(我在评论中提到过,我也提到过编译器可能会优化掉它)。代码中没有影响堆的内存分配。 (仅供参考,我不是那个投反对票的人;我认为这个问题很好,尽管它是基于对变量分配方式的完全误解。)
  • @KenWhite 嗯,谢谢,这正是我想要弄清楚的。
  • @Jerry 字符串变量是一个指针。分配一个局部字符串变量,然后分配一个堆栈指针(或者如果编译器可以在那里优化,那么它可能不能用于托管类型)。字符串的内容存储在堆上。指针指向内容。

标签: delphi loops memory-management heap-memory


【解决方案1】:

现在我很好奇的是堆分配在这两种情况下是如何工作的。

您的示例中没有堆分配(除非DoSomething() 在内部分配内存)。

场景一是在每次循环迭代中直接调用列表项

场景 2 也是如此。

我想知道它是否会在每次循环迭代时添加到堆中并释放。

没有任何东西被添加到堆中。

另一方面,显然有一个堆分配,只需声明一个局部变量。

局部变量分配在堆栈上,而不是上。不过,变量可以指向堆上的内存。场景 2 中的 S 变量确实如此,因为 TObject 派生类始终分配在堆上。 S 只是堆栈上的一个局部变量,指向TSomething 对象占用的堆内存。

我想知道哪种方案在堆分配上执行的负载较重(这是导致性能问题的主要原因之一)?

都没有,因为您的示例中没有堆分配。

【讨论】:

    猜你喜欢
    • 2019-06-11
    • 1970-01-01
    • 2017-11-04
    • 2012-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 2021-07-06
    相关资源
    最近更新 更多