0

I find this affirmative here in the stackoverflow website:

"There's no memory leak.

function TBaseForm.CreateEdit(AOwner: TWinControl;
                              inTop, inLeft, inWidth: integer) : TEdit;
begin
  Result := TEdit.Create(AOwner);
  Result.Parent := AOwner;
  Result.Width  := inWidth;
  Result.Top    := inTop;
  Result.Left   := inLeft;
end;

"

Can anyone confirm it? FastMM is showing a leak when destroying this object. If this is not true how would be the correct why to free this object?

Ps. I can't create the object before and free it as well as the object goes into a list and if I free it just after I add it to the list the pointer in the list will be nil.

Thanks.

The code above is a sample the real code is:

procedure TtvdEventCenter.tvdRegister(const AObject: TComponent; const AEvent: string; const ACallback: TtvdEventDetailedCallback);
var
  aItem: TtvdEventObserver;
begin
  aItem := tvdAddObserver(AObject, AEvent);
  aItem.FtvdDetailedCallback := ACallback;
end;

function TtvdEventCenter.tvdAddObserver(const AObject: TComponent; const AEvent: string): TtvdEventObserver;
begin
  Assert(AObject <> nil);
  Assert(AEvent <> '');

  Result := TtvdEventObserver.Create(Self);
  Result.FtvdObject := AObject;
  Result.FtvdEvent := AEvent;
  AObject.FreeNotification(Self);
  FtvdList.Add(Result);
end;

FastMM Result

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

This block was allocated by thread 0x2A00, and the stack trace (return addresses) at the time was:
404D79 [System.pas][System][@ReallocMem][3935]
452971 [Classes.pas][Classes][TList.SetCapacity][3777]
4526FC [Classes.pas][Classes][TList.Grow][3615]
4524B1 [Classes.pas][Classes][TList.Add][3514]
45FBFB [Classes][TComponent.FreeNotification]
78EA83 [uTvdEventCenter.pas][uTvdEventCenter][TtvdEventCenter.tvdAddObserver][120]
78EE45 [uTvdEventCenter.pas][uTvdEventCenter][TtvdEventCenter.tvdRegister][169]
14D0308 [uTvdParisLiteAlertCenter.pas][uTvdParisLiteAlertCenter][TtvdParisLiteAlertCenter.Create][448]
14CEBAC [uTvdParisLiteAlertCenter.pas][uTvdParisLiteAlertCenter][CreateStvdParisLiteAlertCenter][225]
14DD142 [uTvdParisLiteMainPanel.pas][uTvdParisLiteMainPanel][TtvdParisLiteMainPanel.tvdSetupNonVisualComponents][2315]
14E0E67 [uTvdParisLiteMainPanel.pas][uTvdParisLiteMainPanel][TtvdParisLiteMainPanel.tvdSetup][2660]

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

The allocation number is: 102890

Current memory dump of 256 bytes starting at pointer address 7E64B5F0:
B0 69 79 7E 80 80 80 80 80 80 80 80 80 80 80 80 A2 7D B8 6F 80 80 80 80 00 00 00 00 D1 BE 64 7E
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2A A3 01 00 0A 4D 40 00 DB 7F 40 00 0C 82 40 00
C2 D4 56 00 28 8C 42 00 20 00 64 00 2E 00 44 00 20 00 64 00 2E 00 44 00 2E 00 44 00 2E 00 44 00
00 2A 00 00 00 2A 00 00 26 4D 40 00 95 80 40 00 C1 9C 40 00 09 9C 40 00 D3 64 40 00 16 64 40 00
25 6A 40 00 56 64 40 00 63 64 40 00 37 FF 48 00 07 2A 45 00 12 00 00 00 B0 04 02 00 59 8E 6D 84
60 92 5B 01 80 80 80 80 80 80 80 80 80 80 80 80 80 80 A6 71 92 7B 80 80 00 00 00 00 11 BB 64 7E
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4E A5 01 00 0A 4D 40 00 FF 63 40 00 DA 69 40 00
34 64 40 00 31 67 40 00 68 FC 45 00 3E FD 45 00 08 FB 45 00 9C 55 44 01 DF DE 44 01 34 0E 45 01
°  i  y  ~  €  €  €  €  €  €  €  €  €  €  €  €  ¢  }  ¸  o  €  €  €  €  .  .  .  .  Ñ  ¾  d  ~
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  *  £  .  .  .  M  @  .  Û    @  .  .  ‚  @  .
  Ô  V  .  (  Œ  B  .     .  d  .  .  .  D  .     .  d  .  .  .  D  .  .  .  D  .  .  .  D  .
.  *  .  .  .  *  .  .  &  M  @  .  •  €  @  .  Á  œ  @  .  .  œ  @  .  Ó  d  @  .  .  d  @  .
%  j  @  .  V  d  @  .  c  d  @  .  7  ÿ  H  .  .  *  E  .  .  .  .  .  °  .  .  .  Y  Ž  m  „
`  ’  [  .  €  €  €  €  €  €  €  €  €  €  €  €  €  €  ¦  q  ’  {  €  €  .  .  .  .  .  »  d  ~
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  N  ¥  .  .  .  M  @  .  ÿ  c  @  .  Ú  i  @  .
4  d  @  .  1  g  @  .  h  ü  E  .  >  ý  E  .  .  û  E  .  œ  U  D  .  ß  Þ  D  .  4  .  E  .

Same thing happens in this one (simpler)

function TtvdAvlWelfareMenu.AddMenuItem(const aCaption: string; aTag: Integer; aEvent: TNotifyEvent): TMenuItem;
begin
  Result := TMenuItem.Create(Self);
  Result.Caption := aCaption;
  Result.Tag := aTag;
  Result.OnClick := aEvent;
  Items.Add(Result);
end;

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

This block was allocated by thread 0x2BCC, and the stack trace (return addresses) at the time was:
404D0A [System.pas][System][@GetMem][3693]
4063FF [System.pas][System][TObject.NewInstance][11044]
4069DA [System.pas][System][@ClassCreate][12121]
406434 [System.pas][System][TObject.Create][11059]
4BFFE8 [Menus.pas][Menus][UniqueCommand][695]
4C0558 [Menus.pas][Menus][TMenuItem.Create][941]
129649A [utvdParisLiteAVLWelfarePopupMenu.pas][utvdParisLiteAVLWelfarePopupMenu][TtvdAvlWelfareMenu.AddMenuItem][183]
1295EFD [utvdParisLiteAVLWelfarePopupMenu.pas][utvdParisLiteAVLWelfarePopupMenu][TtvdAvlWelfareMenu.Create][123]
14DDED5 [uTvdParisLiteMainPanel.pas][uTvdParisLiteMainPanel][TtvdParisLiteMainPanel.tvdSetupUnitPopupMenu][2501]
14DE1C5 [uTvdParisLiteMainPanel.pas][uTvdParisLiteMainPanel][TtvdParisLiteMainPanel.tvdSetupVisualComponents][2569]
14E0F03 [uTvdParisLiteMainPanel.pas][uTvdParisLiteMainPanel][TtvdParisLiteMainPanel.tvdSetup][2661]

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

The allocation number is: 109793

Current memory dump of 256 bytes starting at pointer address 7E63B0B0:
30 9A 4B 00 00 00 00 00 24 42 4C 00 B0 A0 67 7E 00 00 00 00 A5 B8 35 F3 00 00 00 00 F0 98 63 7E
00 00 00 00 00 00 00 00 88 2D 41 00 00 00 00 00 D0 AC 01 00 0A 4D 40 00 FF 63 40 00 DA 69 40 00
34 64 40 00 83 66 40 00 60 3A 4C 00 48 3C 4C 00 D4 64 29 01 58 5E 29 01 D5 DE 4D 01 C5 E1 4D 01
CC 2B 00 00 CC 2B 00 00 26 4D 40 00 FA 80 40 00 9C 28 44 01 FD 29 44 01 A3 24 44 01 B2 52 44 01
39 E7 44 01 20 53 46 01 DE D3 4D 01 FB 0E 4E 01 B7 F8 54 01 14 00 00 00 B0 04 02 00 83 75 7F 91
D0 60 44 00 60 29 63 7E 13 00 00 00 1C 00 00 00 00 00 00 00 7C 8A 80 6E 00 00 00 00 31 AB 63 7E
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F5 AB 01 00 79 4D 40 00 71 29 45 00 FC 26 45 00
B1 24 45 00 75 FC 45 00 3E FD 45 00 08 FB 45 00 FC FA 43 01 7A 0F 44 01 BF E4 44 01 5E 11 45 01
0  š  K  .  .  .  .  .  $  B  L  .  °     g  ~  .  .  .  .  ¥  ¸  5  ó  .  .  .  .  ð  ˜  c  ~
.  .  .  .  .  .  .  .  ˆ  -  A  .  .  .  .  .  Ð  ¬  .  .  .  M  @  .  ÿ  c  @  .  Ú  i  @  .
4  d  @  .  ƒ  f  @  .  `  :  L  .  H  <  L  .  Ô  d  )  .  X  ^  )  .  Õ  Þ  M  .  Å  á  M  .
Ì  +  .  .  Ì  +  .  .  &  M  @  .  ú  €  @  .  œ  (  D  .  ý  )  D  .  £  $  D  .  ²  R  D  .
9  ç  D  .     S  F  .  Þ  Ó  M  .  û  .  N  .  ·  ø  T  .  .  .  .  .  °  .  .  .  ƒ  u    ‘
Ð  `  D  .  `  )  c  ~  .  .  .  .  .  .  .  .  .  .  .  .  |  Š  €  n  .  .  .  .  1  «  c  ~
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  õ  «  .  .  y  M  @  .  q  )  E  .  ü  &  E  .
±  $  E  .  u  ü  E  .  >  ý  E  .  .  û  E  .  ü  ú  C  .  z  .  D  .  ¿  ä  D  .  ^  .  E  .
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Icaro
  • 14,585
  • 6
  • 60
  • 75
  • 2
    There is no memory leak in this function as long as the `AOwner` is a control which is being destroyed at some point in your application. – TLama Jan 23 '14 at 02:06
  • 1
    What does FastMM say, exactly? – Blorgbeard Jan 23 '14 at 02:07
  • So from what you are saying TLama is that instead use Self as AOwner I should create a global variable to be the owner of all the object created and when I free it in the Destroy function all the other objects will be destroyed as well? – Icaro Jan 23 '14 at 02:54
  • 1
    @IcaroLavrador: that is not what TLama said. Using `Self` is fine as long as the object represented by `Self` (in your example, a `TtvdEventCenter` object) is freed at some point, which will then free the owned `TtvdEventObserver` object. – Remy Lebeau Jan 23 '14 at 03:46
  • You do have a leak, assuming FastMM is correctly used. – David Heffernan Jan 23 '14 at 07:20

2 Answers2

3

Components have an owner in order to simplify the process of managing their memory.

When a component is created with an Owner component (which means, the constructor´s parameter Owner is not nil), such a component is added to a list in the owner component (property TComponent.Components). From this moment on the programmer does not need to care about releasing the just created component, since it´s owner will free it when the owner itself is freed.

When a component is created without an owner, then the programmer becomes responsible to explicitly free it in some moment.

So, the affirmative about memory leaks you found is correct, but it could be complemented with "as long as AOwner is not nil".

If there is a leak in your code regarding a component, it´s because the owner component is not being freed, so no owned components will be free either. In this cases, you have to look the bug in the owner component´s life cicle, not the owned component´s.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
AlexSC
  • 1,823
  • 3
  • 28
  • 54
0

The reported memory being leaked is allocated inside of the AObject.FreeNotification(Self) call, when growing AObject's internal list of components to notify when AObject is freed. Since that list is being leaked, it stands to reason that AObject is never being freed. In which case, FastMM should also be reporting a leak for the memory used for AObject itself as well.

What does AObject represent exactly? Where and how is it created?

In your second example, the trace suggests the TMenuItem is leaking, because the owning TtvdAvlWelfareMenu is not being freed.

So you are obviously not managing your objects correctly. But you have not shown any of that code, so there is no way to diagnose why.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • AObject is self from the unit calling to register to the Event Center, for exemple: StvdEventCenter.tvdRegister(Self, FtvdEvent, CallbackEvent) – Icaro Jan 23 '14 at 03:52
  • That does not answer my questions about what that object actually is, how that object is created, how/if that object is freed, etc. – Remy Lebeau Jan 23 '14 at 04:50
  • My understand is that this function "function TtvdEventCenter.tvdAddObserver(const AObject: TComponent; const AEvent: string): TtvdEventObserver;" call this function "function TtvdEventCenter.tvdAddObserver(const AObject: TComponent; const AEvent: string): TtvdEventObserver;" that is called by " StvdEventCenter.tvdRegister(Self, FtvdEvent, CallbackEvent)" so AObject = Self where self is the object that is registering to the service, and yes it is freed. Sorry maybe I'm missing something in your question. – Icaro Jan 23 '14 at 04:55
  • 2
    What object is calling `tvdRegister()` to register itself? THAT object is having `FreeNotification()` called on it, and THAT object is the one being leaked. – Remy Lebeau Jan 23 '14 at 05:06
  • A memory leak is a problem of the entire setup. If we can't see the entire lieftime of the object, it is impossible to say where a leak might occur. That is the problem here. The memory dump is irrelevant, also showing one or two functions. – Rudy Velthuis Jan 23 '14 at 10:51