如何自动释放类/对象?

时间:2009-01-06 09:52:34

标签: delphi

在delphi应用程序中自动释放对象有哪些技术?

8 个答案:

答案 0 :(得分:19)

使用接口而不是对象。它们被引用计数,并在引用计数达到0时自动释放。

答案 1 :(得分:12)

我编写了一个函数GC(obj:TObject)(用于Garbage Collect),它接受一个对象并在执行离开当前方法时释放它。它有点像Try Finally Free块的单行速记函数。

而不是:

procedure Test;
var AQuery: TQuery;
begin
  AQuery := TQuery.Create(nil);
  try
    ...
  finally
    FreeAndNil(AQuery);
  end;
end;

我只是:

procedure Test;
var AQuery: TQuery;
begin
  AQuery := TQuery.Create(nil);
  GC(AQuery);
  ...
end;

GC函数只是以接口的形式返回一个对象。

function GC(obj: TObject): IGarbo;
begin
  Result := TGarbo.Create(obj);
end;

因为TGarbo类来自TInterfacedObject,所以当TGarbo对象超出范围时,它将自动被释放。在TGarbo对象的析构函数中,它还释放了在它的构造函数(您在GC函数中传递的对象)中传递给它的对象。

type
  IGarbo = interface
    ['{A6E17957-C233-4433-BCBD-3B53C0C2C596}']
    function Obj: TObject;
  end;

  TGarbo = class(TInterfacedObject, IGarbo)
  private
    FObj: TObject;
  public
    constructor Create(AObjectToGC: TObject);
    destructor Destroy; override;
    function Obj: TObject;
  end;

{ TGarbo }

constructor TGarbo.Create(AObjectToGC: TObject);
begin
  inherited Create;
  FObj := AObjectToGC;
end;

destructor TGarbo.Destroy;
begin
  if Assigned(FObj) then
    FreeAndNil(FObj);
  inherited;
end;

function TGarbo.Obj: TObject;
begin
  Result := FObj;
end;

在不久的将来,陷入Delphi 7的世界并没有看到升级到带有内置垃圾收集的Delphi版本,我沉迷于使用这种简单的方法来轻松释放本地临时对象! :)

答案 2 :(得分:7)

沿着界面,您可以尝试Guard单元中的JclSysUtils功能,这是免费Jedi Code Library的一部分。它允许您将对象与单独的接口引用相关联,因此当该接口引用被销毁时,该对象将随之被销毁。当您无法修改正在使用的类以使其支持自己的接口时,这可能很有用。

var
  G: ISafeGuard;
  foo: TStrings;
begin
  // Guard returns TObject, so a type-cast is necessary
  foo := Guard(TStringList.Create, G) as TStrings;
  // Use the object as normal
  foo.Add('bar');
end; // foo gets freed automatically as G goes out of scope

对象和GetMem分配指针存在重载。还有IMultiSafeGuard,可以确保释放多个对象。

如果你有一个工厂函数,你可能正在创建一个对象,设置它的一些属性,然后返回它。如果在设置属性时发生异常,您将需要确保释放该对象,因为您无法返回该对象。一种方法是这样的:

function Slurp(const source: TFileName): TStrings;
begin
  Result := TStringList.Create;
  try
    Result.LoadFromFile(source);
  except
    Result.Free;
    raise;
  end;
end;

使用Guard,它将成为:

function Slurp(const source: TFileName): TStrings;
var
  G: ISafeGuard;
begin
  Result := Guard(TStringList.Create, G) as TStrings;
  Result.LoadFromFile(source);
  G.ReleaseItem;
end;

ReleaseItem方法撤消ISafeGuard对象的所有权。如果在发生异常之前发生异常,那么当堆栈展开并释放接口时,防护将释放该对象。

答案 3 :(得分:6)

我不得不说,我不喜欢“隐藏”一个物体的自由。传统代码要好得多:

MyObject := TObject.Create;
try
  // do stuff
finally
  FreeAndNil(MyObject);
end;

它不会出错,按预期工作,人们会认识到这种模式。

答案 4 :(得分:5)

使用VCL提供的组件的对象所有权。只要您使用非零所有者创建对象,就不需要明确地释放它们。另请参阅我对this问题的回答。

答案 5 :(得分:2)

这是Delphi的API for Boehm Garbage Collector DLL。 Delphi API由Barry Kelly编写,他现在为CodeGear编写编译器。

答案 6 :(得分:1)

如果你有Delphi 2009,

Smart Pointers工作得非常好。

答案 7 :(得分:-2)

如果你使用Delphi for .Net / Delphi Prism,你会得到Garbage Collection来处理所有的释放。