TTaskBar内存泄漏

时间:2015-02-19 11:01:23

标签: delphi fastmm leakcheck

Embarcadero的TTaskbar有内存泄漏。由于我在表单上删除了此控件,因此每次关闭应用程序时,FastMM都会报告泄漏。

我尝试使用以下代码将FastMM静音:

procedure TMainForm.FormCreate(Sender: TObject);
begin
 fastmm4.RegisterExpectedMemoryLeak(Taskbar);
end;

但它不起作用。如何注册这个泄漏?


  

内存块已泄露。大小是:100

     

该块由线程0xC64分配,并且堆栈跟踪(返回   地址)当时是:406A52 409A7B 409CAC 4283A0

  [System.SysUtils] [System] [System.SysUtils.FmtStr] 409CC6 40D775   7628A65F
  [StretchDIBits的未知功能] 7731594E
  [RtlpNtMakeTemporaryKey的未知功能] 7731594E
  [RtlpNtMakeTemporaryKey的未知功能] 773168F8
  [RtlpNtMakeTemporaryKey的未知功能] 773168DC
  [RtlpNtMakeTemporaryKey的未知功能]

     

该块当前用于类的对象:UnicodeString
  分配编号为:2209

     

内存块已泄露。大小是:36

     

该块由线程0xC64分配,并且堆栈跟踪(返回   地址)当时是:406A52 407D43 40846A 42CD40
  [System.SysUtils] [System] [System.SysUtils.Exception.CreateFmt] 5DEDD7
  [System.Win.TaskbarCore] [System.Win] [System.Win.TaskbarCore.TTaskbarBase.UpdateTab]   610F00
  [Vcl.Taskbar] [Vcl] [Vcl.Taskbar.CheckMDI] 5DF39F
  [System.Win.TaskbarCore] [System.Win] [System.Win.TaskbarCore.TTaskbarBase.ApplyTabsChanges]   610DB8
  [Vcl.Taskbar] [Vcl的] [Vcl.Taskbar.TCustomTaskbar.Initialize]   5EB044
  [Vcl.Forms] [Vcl] [Vcl.Forms.TApplication.Run] 62573A
  [MinimalTemplate.dpr] [MinimalTemplate] [MinimalTemplate.MinimalTemplate] [26]

     

该块当前用于类的对象:ETaskbarException
  分配编号为:2207

     

此应用程序已泄露内存。小块泄漏(不包括指针记录的预期泄漏):

     

21 - 36个字节:ETaskbarException x 1
  85 - 100字节:UnicodeString x 1
  [Vcl.Forms] [Vcl] [Vcl.Forms.TCustomForm.SetVisible] 5F5010

1 个答案:

答案 0 :(得分:11)

此代码中的内存泄露自System.Win.TaskbarCore

procedure TTaskbarBase.UpdateTab;
var
  LpfIsiconic: LONGBOOL;
  LHandle: HWND;
  LFlags: Integer;
begin
  if FTaskbarIsAvailable then
  begin
    LHandle := GetFormHandle;
    if not FRegistered and TaskBar.RegisterTab(LHandle) then
    begin
      TaskBar.SetTabOrder(LHandle);
      TaskBar.SetTabActive(LHandle);
      FRegistered := True;
    end
    else
      ETaskbarException.CreateFmt(SCouldNotRegisterTabException, [TaskBar.LastError]);
....

最后一行创建一个异常,然后对它不执行任何操作。它拥有的异常和字符串被泄露。据FastMM报道。

如果您可以获取地址,可以将这些对象注册为泄露。但是,你不能这样做。无法引用此异常对象。

如果您只是必须避免这种错误报告的泄漏,并且您有意义,那么您需要在项目中包含System.Win.TaskbarCore的固定版本。制作该文件的副本,并将其添加到您的项目中。然后修改代码以修复故障。我的猜测是这样的:

if not FRegistered then
begin
  if TaskBar.RegisterTab(LHandle) then
  begin
    TaskBar.SetTabOrder(LHandle);
    TaskBar.SetTabActive(LHandle);
    FRegistered := True;
  end
  else
    raise ETaskbarException.CreateFmt(SCouldNotRegisterTabException, [TaskBar.LastError]);
end;   

显然,这需要向Embarcadero报告。我建议您提交错误报告。


另一种方法是尽量避免伪造线执行。我相信如果你从.dfm文件中删除这一行,你应该避免虚假行,因此避免泄漏:

Visible = True

只需删除该行,它似乎就是触发器。

请注意,我通过将项目切割成裸露的骨头来解决这个问题。为了重现这个问题,这是所需的最小dfm文件:

object Form1: TMainForm
  Visible = True
  object Taskbar1: TTaskbar
  end
end

使用这个dfm文件没有泄漏:

object Form1: TMainForm
  object Taskbar1: TTaskbar
  end
end

通过将项目缩减至最低限度,我能够找到触发器。我无法强调这种最小化再现技术的价值。


感谢Remy找到此错误的QC报告:QC#128865