I am in the process of creating a small application in Delphi 2006. In one of the classes there is a property of another class. In my onCreate event, I instantiated the objects and also destroy them in the onDestroy event. When I close the application, I get a memory leak warning. I honestly cannot identity the memory leak. Here is the code that I am using, your help will be greatly appreciated.
I can't post an image of the error message, but here is a description.
An unexpected memory leak has occurred. The unexpected small block leaks are:
21 - 28 bytes: TPermanentAddress x 1
Here is the class:
unit uUser;
interface
uses
classes,SysUtils,Dialogs;
type
TAddress = class
private
FStreetAddress : string;
FCity : string ;
FState : string;
FZipCode : string;
procedure setStreetAddress(const Value : string);
procedure setCity(const Value : string);
procedure setState(const Value : string);
procedure setZipCode(const Value : string);
protected
public
property StreetAddress : string read FStreetAddress write setStreetAddress;
property City : string read FCity write setCity;
property State : string read FState write setState;
property ZipCode : string read FZipCode write setZipCode;
end;
type
TPermanentAdddress = class (TAddress)
private
FStartDate : string;
FEndDate : string;
procedure setStartDate(const Value : string);
procedure setEndDate(const Value : string);
protected
public
property StartDate : string read FStartDate write setStartDate;
property EndDate : string read FEndDate write setEndDate ;
end;
type
TUser = class(TObject)
private
FFirstName : string;
FAddress : TPermanentAdddress;
procedure setFirstName(const Value : string);
procedure setAddress(const Value : TPermanentAdddress);
protected
public
constructor Create(); reintroduce; overload;
destructor Destroy(); override;
property FirstName : string read FFirstName write setFirstName;
property Address : TPermanentAdddress read FAddress write setAddress;
end;
implementation
procedure TAddress.setStreetAddress(const Value : string);
begin
FStreetAddress := value;
end;
procedure TAddress.setCity(const Value : string);
begin
FCity := Value;
end;
procedure TAddress.setState(const Value : string);
begin
FState := Value;
end;
procedure TAddress.setZipCode(const Value : string);
begin
FZipCode := Value;
end;
//Permanent Address
procedure TPermanentAdddress.setStartDate(const Value : string);
begin
FStartDate := value;
end;
procedure TPermanentAdddress.setEndDate(const Value : string);
begin
FEndDate := Value;
end;
//tvxpatient
procedure TUser.setFirstName(const Value : string);
begin
FFirstName := Value;
end;
procedure TUser.setAddress(const Value : TPermanentAdddress);
begin
FAddress := Value;
end;
constructor TUser.Create();
begin
FAddress := TPermanentAdddress.Create;
end;
destructor TUser.Destroy();
begin
//FAddress.Free;
end;
end.
Here is the Form:
unit Home;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, uUser, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
protected
public
{ Public declarations }
aUser : TUser;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
addr : TPermanentAdddress;
begin
aUser := TUser.Create;
aUser.Address := TPermanentAdddress.Create;
aUser.FirstName := 'test';
aUser.Address.StartDate := '03/10/2015';
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
aUser.Address.Free; // I am destroying it here, so I thought.
aUser.Free;
end;
end.
In the project, I turned on ReportMemoryLeaksOnShutdown.
program Testing;
uses
Forms,
Home in 'Home.pas' {Form1},
uUser in 'uUser.pas';
{$R *.res}
begin
ReportMemoryLeaksOnShutdown := DebugHook <> 0;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
destructor TUser.Destroy();
begin
//FAddress.Free;
end;
Here you fail to destroy FAddress
. Hence the memory leak.
Your should also call the inherited destructor. It should look like this:
destructor TUser.Destroy;
begin
FAddress.Free;
inherited;
end;
On top of this, you are wrong to create Address
twice. Instead of:
procedure TForm1.FormCreate(Sender: TObject);
var
addr : TPermanentAdddress;
begin
aUser := TUser.Create;
aUser.Address := TPermanentAdddress.Create;
aUser.FirstName := 'test';
aUser.Address.StartDate := '03/10/2015';
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
aUser.Address.Free; // I am destroying it here, so I thought.
aUser.Free;
end;
You need:
procedure TForm1.FormCreate(Sender: TObject);
begin
aUser := TUser.Create;
aUser.FirstName := 'test';
aUser.Address.StartDate := '03/10/2015';
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
aUser.Free;
end;
Personally I would use the constructor/destructor of TForm1
rather than OnCreate
and OnDestroy
to managed owned objects.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.