什么时候动态数组会收集垃圾?

时间:2011-11-08 05:12:00

标签: delphi

动态数组是引用计数的,因此编译器会自动释放内存。我的问题是,什么时候发生这种自动释放?它会立即发生,还是在包含程序结束时发生?

这是一个具体的例子

procedure DoStuff;
var data:TBytes;
begin
  data:=GetData; // lets say data now contains 1 Gig of data.
  DoStuffWithData(data);
  // I now want to free up this 1Gig of memory before continuing.
  // Is this call needed, or would the memory be freed in the next line anyway?
  Finalize(data); 

  data:=GetMoreData; // The first array now has no remaining references
  DoStuffWithData(data);
end

对Finalize()的调用是否冗余?

2 个答案:

答案 0 :(得分:11)

Finalize的调用并不是多余的。确实,动态数组的引用计数将在下一行递减(因此可能会破坏数组),但这只会在分配新动态数组后发生。在返回GetMoreData之前,但在分配之前,内存中将有两个动态数组。如果你事先手动销毁第一个,那么你一次只能在内存中有一个数组。

存储在data中的第二个数组将在DoStuff返回时被销毁(假设DoStuffWithData未存储动态数组的副本参考其他地方,增加其参考数量。)

答案 1 :(得分:1)

  

何时发生这种自动释放?是立即发生,还是在包含程序结束时发生?

当引用计数设置为0时,将释放与托管类型(动态数组属于此类)关联的动态内存。这可能发生在以下几点:

  1. 为参考变量分配了一个新值。对Finalize的调用可以被认为是新值为零的特殊情况。
  2. 参考变量超出范围。例如:
    • 达到功能的退出;局部变量超出范围。
    • 对象被销毁,其成员超出范围。
    • 使用Dispose函数销毁指向记录的指针;记录的所有字段都超出了范围。
    • 最终确定一个单位,并最终确定单位中定义的所有全局变量。
  3. 请注意,上述各种情况仅导致在正在完成或正在离开作用域的引用是最后剩余引用时释放内存。换句话说,当引用计数为1时。

    在您的特定示例中,假设删除了Finalize,您将创建一个新的动态数组并将其分配给已拥有动态数组的变量。然后它落入上面列表中第1项描述的类中。因此,在这种意义上,对Finalize的调用是多余的。

    Rob已经解释了分配和释放发生的顺序,这是一个好点。据我所知,这是一个未明确记录的实现细节。但是,如果细节有所改变,我会感到震惊。