3

I have encountered a memory leak problem with a Delphi 7 application(CLX), with a piece of code like the following :

unit Unit2;

interface

  uses ECRClass, ECR_Text,  SysUtils, Types, Classes, Variants, Math;

  type tLeakClass = class
  private
  fsType : integer;

  public
  fsPrinter : TECR_Class;

  published
  constructor Create (AOwner : TComponent);
  destructor Destroy();
  end;


implementation

   constructor tLeakClass.Create (AOwner : TComponent);
   begin
   fsPrinter := TECR_Text.Create(AOwner);
   end;

   destructor tLeakClass.Destroy();
   begin
     fsPrinter.Free
   end;

end.

the object fsPrinter result leaked even if it is freed at the moment that the main form(TForm) close :

unit Unit1;

interface

uses
  SysUtils, Types, Classes, Variants, QTypes, QGraphics, QControls, QForms, 
  QDialogs, QStdCtrls, Unit2;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    tleak : tLeakClass;
  end;

var
  Form1: TForm1;

implementation

{$R *.xfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
     tLeak := tLeakClass.Create(Self);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
   tleak.Free
end;

end.

Here's the report of the leak by FastMM4 :

A memory block has been leaked. The size is: 740

This block was allocated by thread 0xBA8, and the stack trace (return addresses) at the time was:
402F1C [system.pas][System][@GetMem][2439]
403C77 [system.pas][System][TObject.NewInstance][8360]
404012 [system.pas][System][@ClassCreate][9019]
502F15 [ECR_Text.pas][ECR_Text][TECR_Text.Create][101]
403C80 [system.pas][System][TObject.NewInstance][8360]
404012 [system.pas][System][@ClassCreate][9019]
5030C6 [Unit2.pas][Unit2][tLeakClass.Create][24]
43856C [QStdCtrls.pas][QStdCtrls][2863]
503300 [Unit1.pas][Unit1][TForm1.Button1Click][30]
447076 [QControls.pas][QControls][TControl.Click][1977]
43858C [QStdCtrls.pas][QStdCtrls][TButton.Click][2871]

The block is currently used for an object of class: TECR_Text

Here you can download a full SSCCE example of a project that represent the problem(to run the example one click on the button and close the form).

Why the fsPrinter object leaks ? How can I avoid the leak ?

aleroot
  • 71,077
  • 30
  • 176
  • 213
  • If you click that button several times, you'll *overwrite* the reference to the `TLeakClass` object in the `TLeak` field, what turns those objects to orphans. You just need to keep reference to all those objects, or just call `TLeak.Free` before you create the new one. – TLama Mar 31 '13 at 15:40
  • No, I click only one time. It is only an example to demostrate a problem. You have to click one time on the button and then close the form ... – aleroot Mar 31 '13 at 15:46
  • Well, then might have been better to use `OnCreate` event of a form for this. – TLama Mar 31 '13 at 15:48
  • This is a much better example. Well done. My advice for building really small SSCCEs is to make console applications. – David Heffernan Mar 31 '13 at 15:48

1 Answers1

6

You destructor is declared incorrectly. You wrote:

destructor Destroy();

But you must override the virtual destructor declared in TObject. If you don't then your destructor will not be called by Free which calls the virtual destructor declared in TObject.

Fix it like this:

destructor Destroy(); override;

Although it doesn't matter in this case, you should get in to the habit of calling the inherited constructors and destructors in your constructors and destructors. That way, when you derive from a class that does more than TObject does in its constructors and destructors, you will make sure the superclass code runs.

constructor tLeakClass.Create (AOwner : TComponent);
begin
  inherited Create;
  fsPrinter := TECR_Text.Create(AOwner);
end;

destructor tLeakClass.Destroy();
begin
  fsPrinter.Free;
  inherited;
end;

The FastMM report is a bit odd though. It reports that the TECR_Text object is leaked. But since you created that as owned by the form, the form should take it down. The object that is clearly leaked in the code in the question is the instance of tLeakClass

So I suspect that there are other problems in the classes that we cannot see. Quite possibly you made the same error and omitted the override on the destructors of the classes that we cannot see.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Not in my version of the code. Of course I don't have the same classes as you. This is a better example, but I cannot compile it. I have to substitute something else for `TECR_Text`. You really need to provide an example that I can compile as is. Make it a console app, and one that only uses standard classes. – David Heffernan Mar 31 '13 at 15:57
  • Oh, yes sorry. Now I have understood ! Sorry but I'm quite new to Delphi :-) – aleroot Mar 31 '13 at 15:57
  • By the way, learning how to make a really good SSCCE won't just help you ask good questions. The main benefit is that you will be able to look at a really small amount of code that contains a flaw. And that hugely increases your chance of finding the problem. In my opinion this is the biggest benefit of writing good SSCCEs. – David Heffernan Mar 31 '13 at 15:59