在Delphi中超出范围的对象会发生什么?

时间:2009-03-11 19:23:22

标签: delphi scope

当在函数和函数中创建的对象完成时,如果未明确销毁该对象会发生什么?

当它们超出范围时是否需要销毁所有变量,或者当它们超出范围时是否需要处理它们?

例如,在调用custom_function之后,locallist会发生什么?

function TForm1.custom_function(string: test_string): boolean;
var locallist: TStringList;
begin
  locallist := TStringList.Create;
  // do a bunch of stuff here, but don't destroy locallist
  return true;
end;

5 个答案:

答案 0 :(得分:16)

您将收到内存泄漏。

正确的模式是

myObject := TObject.Create;
try
  //do stuff
finally
  myObject.Free;
end;

此外,如果您需要稍后测试对象是否已被释放,则使用FreeAndNil(myObject)。它也会将变量设置为nil,因此您可以稍后进行测试。

答案 1 :(得分:11)

正如其他海报所指出的那样,需要明确释放这些对象。这通常是通过使用try..finally块手动完成的,如Ray所示。但是,您应该注意到例外情况。

组件(TComponent descendants)将Owner参数传递给它们的构造函数。如果所有者不是 nil ,则所有者组件将获得新组件的所有权,并在获取时释放它。这就是为什么你不必清理你自己的表格;它们连接到Application对象,它知道如何在程序完成时释放本身。但是,如果在运行时创建组件,则需要为其指定所有者或将 nil 传递给构造函数,然后自行释放它。 不要通过向所有者释放组件来混合两者。在某些情况下可能导致双重自由条件。

实现引用计数的接口对象(大多数是TInterfacedObject后代)如果您将它们专门用作接口(而不是对象),则由引用计数机制释放。当最后一个接口引用它们时,它们会自动释放。除去。如果已将TInterfacedObject分配给接口引用,请不要手动释放它。这将引发异常。此外,请注意,并非所有带接口的对象都实现引用计数。大部分只是来自TInterfacedObject的那些。

创建一个对象,使用try..finally块然后释放它并不总是切实可行。有时这对你正在做的事情不起作用,特别是如果你将对象分配给某种列表(并且制作了很多它们。)在这种情况下,使用TObjectList是个好主意(或者更好的是,如果你有D2009,一个TObjectList),其OwnsObjects属性设置为 true 。这会导致列表成为其中对象的所有者,并在释放时释放它们,就像组件一样。同样,如果对象属于对象列表,则不要手动释放对象。

动态数组(包括字符串)由编译器使用引用计数系统进行管理,并且大多数其他类型的变量在堆栈上分配。你永远不必担心手动释放除了对象之外的任何东西,除非你正在玩指针。

这可能听起来很复杂,但你很快就会习惯它。请记住,每个对象都由以下三种内容之一拥有:另一个对象,接口引用计数系统或您的代码,并且所有者应在不再需要时释放所有对象。没有什么可以试图释放其他东西所拥有的东西。 (你不会偷。)记住这些指导方针,你最终会得到良好的记忆管理。您还可以在DPR的主例程中设置“ReportMemoryLeaksOnShutdown:= true”以获得更多帮助。

答案 2 :(得分:5)

它变成了泄露的记忆。

您通常应该围绕这样的分配:

locallist := TStringList.Create;
try
     // work with locallist here
  finally
     locallist.Free;
  end; 

Delphi中唯一一种在超出范围时有自杀倾向的引用是接口引用。

答案 3 :(得分:3)

对不起,内存没有回收。您需要使用locallist.Free;

显式释放此对象

答案 4 :(得分:3)

这将导致memory leak仅在应用程序结束时销毁。要检测这些,您可以使用像FastMM这样的内存管理器。

请注意,您可以使用Destroy或Free方法销毁对象。如果对象是nil,第一个将给出错误,后者不会 - 它等于

if Assigned(Object) then Object.Destroy;