当我释放Delphi中可能不存在的内存时会发生什么?

时间:2014-03-21 17:23:57

标签: delphi memory-management garbage-collection

Delphi没有垃圾收集器,所以来自Java背景这是一个真正的痛苦。

通常,为了摧毁一些我不再使用的记忆,我会使用:

if (SomeMemory <> nil) then
  SomeMemory.Free

如果我在删除之前没有检查nil会怎样?

此外,为什么有人会想要处理所有这些&#34;垃圾收集&#34;他自己?为什么在Delphi的所有编译选项中,没有Garbage Collector = true

4 个答案:

答案 0 :(得分:7)

TObject.Free的代码如下所示:

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

因此无需检查nil。如果你试图释放未初始化的变量,你仍然会遇到麻烦,因为这将导致AV。检查nil(或Assigned)显然也无法帮助您。但是,如果您尝试执行此操作,编译器将发出警告。

回答你的第二个问题

  

为什么在Delphi的所有编译选项中,没有Garbage Collector = true

简单的答案是Delphi没有这样的垃圾收集器。某些托管类型(如字符串,动态数组等)实现编译器管理的自动引用计数,并且当引用计数降至零时,这些对象将自动释放。对于所有其他非托管对象,开发人员有责任在不再需要对象实例时对其进行适当清理。

这不是想要必须管理应用程序内存的问题,这只是你需要的事情。

答案 1 :(得分:6)

nil之前检查Free是多余的。如果引用为nil,那么已经安全地调用它上面的Free。如果引用不是 nil,那么在其上调用Free的安全性将保持不变,完全取决于变量是否包含有效引用。

例如:

SomeMemory := nil;
SomeMemory.Free; // This is safe.

SomeMemory := TObject.Create;
SomeMemory.Free; // This is safe
Assert(SomeMemory <> nil);
SomeMemory.Free; // This is an error (EInvalidOperation)

在第一个块中,我们不检查变量是否为null,但是对Free的调用是完全安全的。它什么都不做。在第二个块中,我们看到变量保持非null,但在其上调用Free会产生异常。

答案 2 :(得分:4)

在Delphi中有一种非常直接的方式(垃圾收集):使用接口指针。通过使用最终从IInterface(或IUnknown基本上是相同的东西)派生的类型的变量,Delphi将保持对引用的近似计数,并在最后一个引用时释放/销毁/释放实例已移除。除了实例创建和其他一些东西之外,使用接口指针几乎与使用对象引用相同。

在Nick Hodges最近的工作Coding In Delphi中,有很多关于这种编程技术,以及它与抽象,泛型,单元测试和依赖注入的关系。

对象引用也是new versions of Delphi for other platforms will have ARC(自动引用计数),现在就像接口一样操作。 (废除免费方法,但这是另一个故事。)

答案 3 :(得分:2)

您可以随时咨询documentation以回答此类问题。这是我的重点:

  

使用Free来销毁对象。如果对象引用不是nil,则自动调用析构函数。在运行时实例化的任何没有所有者的对象应该通过调用Free来销毁,以便可以正确处理它并释放它的内存。 与Destroy不同,即使对象为零,Free也是成功的;如果对象从未初始化,则Free不会导致错误。

在此处查找有关此问题的更完整的讨论:Why should I not use "if Assigned()" before using or freeing things?