Friday, 21 November 2008

Crear un Garbage Collector en Delphi

Al igual que en java o en C++, los objetos se destruyen automáticamente cuando ya nadie los apunta. En delphi no pasa lo mismo, y siempre hay que controlar sus creaciones y destrucciones. Este ejemplo tomado de delphi 3000, nos permite utilizar un patron proxy (proxy object). Este ejemplo pretende utilizar las interfaces, ya que estas disponen de un contador de referencias. Cuando este llega a cero, el objeto se destruye. Esta es la manera de utilizar el proxy object. Creamos el objeto, y lo asociamos a nuestro proxy. Una vez nuestro objeto no tenga ningún apuntador, liberará nuestro objeto.
El código de la unit GarbageCollector es el siguiente:



unit GarbageCollector;

interface

uses
sysUtils;

type
ISafeGuard = type IUnknown;

function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject;

implementation

type
TSafeGuard = class(TInterfacedObject, ISafeGuard)
private
FObj: TObject;
public
constructor Create(Obj: TObject);
destructor Destroy; override;
end;

constructor TSafeGuard.Create(Obj: TObject);
begin
FObj := Obj;
end;

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

function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject;
begin
Result := Obj;
SafeGuard := TSafeGuard.Create(Obj);
end;

end.


Si creamos una pequeña clase para hacer la prueba:


type
TClass1 = Class(TObject)
id : integer;
prop1 : string;
End;


Creamos un par de botones en un proyecto, y creamos los diferentes objetos, uno sin el garbage collector y otro con el proxy:


procedure TForm1.Button1Click(Sender: TObject);
var
objClass1 : TClass1;
begin
objClass1 := TClass1.Create();
objClass1.id := 1;
objClass1.prop1 := 'P1';
end;

procedure TForm1.Button2Click(Sender: TObject);
var
objClass1 : TClass1;
SafeGuard : ISafeGuard;
begin
objClass1 := TClass1(Guard(TClass1.Create, SafeGuard));
objClass1.id := 1;
objClass1.prop1 := 'P1';
end;



En el primer caso, al cerrar la aplicación, si tenemos activada la opción:
ReportMemoryLeaksOnShutDown := true;
obtenemos:


En el segundo caso, el objeto se elimina automáticamente. El ejemplo es válido siempre que nuestro objeto provenga de una clase heredada de TObject.

0 comments:

Post a Comment