I am reading Hodges book "More Coding in Delphi", section on Factory Pattern.
Trying to learn stuff. Broke down my code into small unit.
I use ReportMemoryLeaksOnShutDown := True; and fallowing code produces me a memory leak. Why does it occur and how do I fix it?
unit Unit2;
interface
uses
Generics.Collections, System.SysUtils;
type
TGatewayTpe = (gtSwedbank, gtDNB);
type
TBaseGateway = class
end;
type
TSwedbankGateway = class(TBaseGateway)
end;
type
TGatewayFunction = reference to function: TBaseGateway;
type
TGatewayTypeAndFunction = record
GatewayType: TGatewayTpe;
GatewayFunction: TGatewayFunction;
end;
type
TGatewayFactory = class
strict private
class var FGatewayTypeAndFunctionList: TList<TGatewayTypeAndFunction>;
public
class constructor Create;
class destructor Destroy;
class procedure AddGateway(const AGatewayType: TGatewayTpe;
const AGatewayFunction: TGatewayFunction);
end;
implementation
class procedure TGatewayFactory.AddGateway(const AGatewayType: TGatewayTpe;
const AGatewayFunction: TGatewayFunction);
var
_GatewayTypeAndFunction: TGatewayTypeAndFunction;
begin
_GatewayTypeAndFunction.GatewayType := AGatewayType;
_GatewayTypeAndFunction.GatewayFunction := AGatewayFunction;
FGatewayTypeAndFunctionList.Add(_GatewayTypeAndFunction);
end;
class constructor TGatewayFactory.Create;
begin
FGatewayTypeAndFunctionList := TList<TGatewayTypeAndFunction>.Create;
end;
class destructor TGatewayFactory.Destroy;
begin
FreeAndNil(FGatewayTypeAndFunctionList);
end;
initialization
TGatewayFactory.AddGateway(
gtSwedbank,
function: TBaseGateway
begin
Result := TSwedbankGateway.Create;
end
);
end.
This is a compiler defect. Defining an anonymous method in the initialization section of the unit appears to lead to that anonymous method not being finalized, and so leaked. In this case I would work around the issue by moving the code from the initialization section to the class constructor.
So, remove the initialization section completely, and change the class constructor to be like this:
class constructor TGatewayFactory.Create;
begin
FGatewayTypeAndFunctionList := TList<TGatewayTypeAndFunction>.Create;
AddGateway(
gtSwedbank,
function: TBaseGateway
begin
Result := TSwedbankGateway.Create;
end
);
end;
Here is the simplest reproduction that I can concoct:
unit Unit1;
interface
implementation
type
TProc = reference to procedure;
var
Foo: TProc;
initialization
ReportMemoryLeaksOnShutdown := True;
Foo := procedure begin end;
end.
When you include this unit in a project, the anonymous method is reported as being leaked.
But this variant does not report a leak:
unit Unit1;
interface
implementation
type
TProc = reference to procedure;
var
Foo: TProc;
procedure DoInit;
begin
Foo := procedure begin end;
end;
initialization
ReportMemoryLeaksOnShutdown := True;
DoInit;
end.
The defect was fixed in XE8.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With