Delphi中的函数内部泄漏

时间:2014-01-23 02:04:14

标签: function delphi memory-leaks scope delphi-xe

我在stackoverflow网站上发现这是肯定的:

“没有内存泄漏。

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;

任何人都可以确认吗? FastMM在销毁此对象时显示泄漏。如果不是这样,那么为什么要释放这个对象是正确的呢?

聚苯乙烯。我之前无法创建对象并释放它以及对象进入列表,如果我在将其添加到列表后将其释放,则列表中的指针将为零。

感谢。

上面的代码是真实代码的示例:

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结果

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  .

同样的事情发生在这个(更简单的)

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  .

2 个答案:

答案 0 :(得分:3)

组件拥有所有者,以简化管理内存的过程。

使用Owner组件创建组件时(这意味着构造函数的参数Owner不是nil),这样的组件将添加到owner组件的列表中(property { {1}})。从这一刻开始,程序员不需要关心释放刚创建的组件,因为它的所有者将在释放所有者本身时释放它。

在没有所有者的情况下创建组件时,程序员有责任在某个时刻明确释放它。

因此,您发现的内存泄漏肯定是正确的,但只要TComponent.Components不是AOwner“就可以用补充。

如果您的代码中有关于组件的泄漏,那是因为没有释放所有者组件,因此也没有自有组件也是免费的。在这种情况下,您必须查看所有者组件生命周期中的错误,而不是拥有的组件。

答案 1 :(得分:0)

AObject.FreeNotification(Self)的内部组件列表在AObject被释放时通知时,报告的内存泄漏是在AObject调用内部分配的。由于该列表被泄露,因此AObject永远不会被释放。在这种情况下,FastMM也应报告用于AObject本身的内存泄漏。

AObject到底代表什么?它在哪里以及如何创建?

在您的第二个示例中,跟踪表明TMenuItem正在泄漏,因为没有释放拥有TtvdAvlWelfareMenu

所以你显然没有正确管理你的对象。但是你没有显示任何代码,所以没有办法诊断原因。