【问题标题】:When exactly does a dynamic array get garbage collected?动态数组究竟什么时候被垃圾回收?
【发布时间】:2011-11-08 05:11:59
【问题描述】:

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

这是一个具体的例子

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() 的调用是多余的吗?

【问题讨论】:

    标签: delphi


    【解决方案1】:

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

    您存储在data 中的second 数组将在DoStuff 返回时被销毁(假设DoStuffWithData 不会在别处存储动态数组引用的副本,从而增加其引用计数)。

    【讨论】:

    • 澄清一下,在这种情况下,分配给data 将是当您在GetMoreData 中分配/SetLength Result 时。从函数返回的动态类型的工作方式如下:GetMoreData(var Result: TBytes);
    【解决方案2】:

    这种自动释放的具体时间是什么时候?它是立即发生还是在包含过程结束时发生?

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

    1. 为引用变量分配了一个新值。可以将 Finalize 调用视为新值为 nil 的特殊情况。
    2. 引用变量超出范围。例如:
      • 到达函数的出口;局部变量超出范围。
      • 对象被销毁,其成员超出范围。
      • 使用 Dispose 函数销毁指向记录的指针;记录的所有字段都超出范围。
      • 一个单元已完成,并且该单元中定义的所有全局变量都已完成。

    请注意,上述各种情况仅在正在完成或正在离开范围的引用是最后一个剩余引用时才导致内存被释放。也就是说,当引用计数为 1 时。

    在您的具体示例中,假设 Finalize 已删除,您将创建一个新的动态数组并将其分配给已包含动态数组的变量。这属于上面列表中第 1 项所描述的类别。所以从这个意义上说,对 Finalize 的调用是多余的。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-30
      • 1970-01-01
      • 2015-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多