Question

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  .
Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top