Kennisbank

Smartpointers in Delphi

Zoals je misschien weet heeft Delphi geen garbare collection. ARC zal snel verwijderd worden van de niet-Windows compiler. Delphi heeft dus geen structuur voor het automatisch opruimen van objecten. We hebben onderzoek gedaan om te zien of Smartpointers geschikt zijn voor het automatisch opruimen van objecten. Het concept van Smartpointers is ontleend aan C++ en is in Delphi voor het eerst geïntroduceerd door Barry Kelly. Het Spring4D framework heeft ook een implementatie van Smartpointers.

Om een voorbeeld te geven van het gebruik van Smartpointers bekijken we een aantal codes:

var
  s: TStringList;
begin
  s := TStringList.Create;
try
  DoSomething(s);
finally
  s.Free;
end;

Met Smartpointers ziet de code er zo uit:

var
  s: IShared<TStringlist>;
begin
  s := Shared.Make(TStringList.Create);
  DoSomething(s);
end;

We hebben een testprogramma geschreven om een complexer scenario te testen. Hier is de code van het testprogramma:

program TestSmartPointer;

{$APPTYPE CONSOLE}

uses
  Spring,
  Diagnostics,
  Classes,
  SysUtils,
  System.Generics.Collections;

type
  TTestObj = class
  private
    FDescription: string;
  public
    property Description: string read FDescription write FDescription;
    destructor Destroy; override;
  end;

  TTestList = class(TList<IShared<TTestObj>>)
  public
    destructor Destroy; override;
  end;

procedure Test_SmartPointer;
var
  lTestList: IShared<TTestList>;
  lTestObj: IShared<TTestObj>;
  i: integer;
begin
  writeln('SmartPointer test started');
  lTestList := Shared.Make(TTestList.Create);
  for i := 1 to 10 do
  begin
    lTestObj := Shared.Make(TTestObj.Create);
    lTestObj.Description := i.ToString;
    writeln(format('TestObj with description %s added to Testlist', [lTestObj.Description]));
    lTestList.Add(lTestObj);
  end;
  
  for lTestObj in lTestList do
    writeln(format('Item %d of Testlist has value %s', lTestList.IndexOf(lTestObj), lTestObj.Description));

  writeln('SmartPointer test finished');
end;

{ TTestObj }

destructor TTestObj.Destroy;
begin
  writeln(format('TestObj with description %s is destroyed', [FDescription]));
  inherited;
end;

{ TTestList }

destructor TTestList.Destroy;
begin
  writeln('TTestList is destroyed');
  inherited;
end;

begin
  Test_SmartPointer;
  readln;
end.

In dit programma wordt een generieke lijst TTestList gevuld met TTestObj objecten. Let op de verklaring van de TTestList:

TTestList = class(TList<IShared<TTestObj>>)

De uitvoer van dit testprogramma staat in de onderstaande afbeelding.

Zoals je kunt zien zijn de objecten gefreed na de ‘SmartPointer-test’ regel. Dus als de Test_SmartPointer procedure klaar is, vallen de lokale variabelen buiten de scope en worden ze automatisch opgeruimd. Dit werkt goed.
We hebben ook de prestaties en het gebruikte geheugen getest. De resultaten zijn als volgt:

In de snelheidstest werden 100.000 lijsten gemaakt en elke lijst werd gevuld met 100 items. De smartpointers zijn 29,17% langzamer dan wanneer de klassieke techniek wordt gebruikt.
In de memorytest werd 1 lijst aangemaakt met 100.000 items. Wanneer de lijst volledig gevuld was, werd het geheugen van het programma gemeten. De smartpointers gebruiken 26,94% meer geheugen dan wanneer de klassieke techniek wordt gebruikt. Dit zijn aanzienlijke verschillen.

Conclusie

Smartpointers werken technisch prima. De objecten worden vrijgemaakt zoals verwacht. Er is echter een aanzienlijk nadeel als het gaat om snelheid en gebruikt geheugen. Daarnaast moet elk object worden gedeclareerd met IShared<object> en aangemaakt met Shared.Make(object.create). Onze aanbeveling van smartpointers is dat het een beetje te veel overhead in performance en code is om te worden gebruikt als een eenvoudig te gebruiken algemene stucture voor het automatisch vrijmaken van objecten in Delphi.

Referenties:

https://blog.marcocantu.com/blog/2018-october-Delphi-ARC-directions.html

http://blog.barrkel.com/2008/09/smart-pointers-in-delphi.html

https://delphisorcery.blogspot.com/2015/01/smart-pointers-in-delphi.html

https://en.delphipraxis.net/topic/402-smart-pointers-generics-vrs-non-generic-implementastion/

Contact

Laat ons helpen jouw ambities concreet te maken.