【发布时间】: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