Does Delphi have Garbage Collection?
6 Answers
Simple answer No.
Delphi is not a complete garbage collection language, user-defined types should be manually allocated and deallocated. It only provide automatic collection, for a few built-in types, such as strings, dynamic arrays and interfaces for ease of use.
But you can use interfaces which uses reference counting for garbage collection for some extent.
Yes, it does.
Delphi Win32 does not include a garbage collector out of the box so the other answers to this question are technically correct. However, this doesn't imply that it isn't possible or that one doesn't already exist. Thanks to Delphi's replaceable memory manager Barry Kelly implemented a fully functional wrapper for the Boehm garbage collector back in 2004.
It includes sample code demonstrating its use (basically creating unassigned objects and watching the GC chew them up). There are more advanced GCs than the Boehm GC but this clearly demonstrates its possible and it can be used almost transparently. You just add the gc unit to the beginning of your project's uses clause.
And while I've not heard of any projects attempting it there is nothing preventing someone from wrapping or porting a more advanced gc.
In the usual sense of garbage collection, where the runtime detects unreferenced objects and destroys them or otherwise reclaims unused resources, no, Delphi does not have garbage collection.
If you use native Win32 Delphi, then the closest you have to garbage collection is the various reference-counted types, including strings, interfaces, variants, and dynamic arrays. Those types will get cleaned up automatically when your program determines that they are no longer being used, but it does that by keeping a reference count as those objects enter and leave the current scope. You also have the concept of ownership, which will destroy owned components when the owner is destroyed.
If you use Delphi for .Net, then you implicitly have the garbage collection of the underlying runtime.
Delphi Win32/64 does not have a garbage collector. You can however take advantage of Delphi native references counting mechanism to have instances released automatically by using interfaces.
The differences between a garbage collector and a reference counting mechanism is that you will have to deal with circular references, i.e. if A and B instances reference each other, you need to manually break the cycle for A or B to be released.
Yes! Look at this class
unit uGC;
interface
uses
System.Generics.Collections, Rtti, System.Classes;
type
TGarbageCollector = class(TComponent)
public
const
DEFAULT_TAG = 'DEFAULT_TAG';
private
items: TDictionary<TObject, string>;
public
destructor Destroy; override;
constructor Create(AOwner: TComponent); override;
function Add<T>(item: T): T; overload;
function Add<T>(item: T; const tag: string): T; overload;
procedure Collect(const tag: string);
end;
var
GC: TGarbageCollector;
implementation
uses
System.Types, System.SysUtils;
constructor TGarbageCollector.Create(AOwner: TComponent);
begin
inherited;
items := TObjectDictionary<TObject, string>.Create([doOwnsKeys]);
end;
destructor TGarbageCollector.Destroy;
begin
items.free();
inherited Destroy;
end;
function TGarbageCollector.Add<T>(item: T): T;
begin
result := Add(item, DEFAULT_TAG);
end;
function TGarbageCollector.Add<T>(item: T; const tag: string): T;
var
obj: TObject;
v: TValue;
begin
v := TValue.From<T>(item);
if v.IsObject then
begin
items.add(v.AsObject, tag);
result := item;
end
else
raise Exception.Create('not an Object');
end;
procedure TGarbageCollector.Collect(const tag: string);
var
key: TObject;
item: TPair<TObject, string>;
gcList: TList<TObject>;
begin
gcList := TList<TObject>.Create();
try
for item in items do
begin
if (item.Value = tag) then
gcList.add(item.Key);
end;
for key in gcList do
items.remove(key);
finally
gcList.free();
end;
end;
end.
Create it like this
program GarbageCollector;
uses
Vcl.Forms,
uMain in 'uMain.pas' {Main},
uGC in 'uGC.pas',
uSomeClass in 'uSomeClass.pas';
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
GC := TGarbageCollector.Create(Application); // <<<
Application.CreateForm(TMain, Main);
Application.Run;
end.
Use it like this
someInstance := GC.Add(TSomeClass.Create(nil), 'TSomeClassTag');
// do smth with someInstance
//now destroy
GC.Collect('TSomeClassTag');
//
anotherInstance := GC.Add(TSomeClass.Create(nil), 'TSomeClassTag');
// do smth with anotherInstance
// not destroying here - will be destroyed on app destroy...