内存泄漏



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

我试图用这段代码将 FastMM 静音:

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

但它行不通。如何记录此泄漏?


内存块已泄露。尺寸为:100

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

[System.SysUtils][系统][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.SysUtils.Exception.CreateFmt] 5DEDD7
[系统.赢.任务栏核心][系统赢][System.Win.TaskbarCore.TTaskbarBase.UpdateTab] 610F00
[Vcl.任务栏][Vcl][Vcl.Taskbar.CheckMDI] 5DF39F
[系统.赢.任务栏核心][系统赢][System.Win.TaskbarCore.TTaskbarBase.ApplyTabsChanges] 610DB8
[Vcl.任务栏][Vcl][Vcl.Taskbar.TCustomTaskbar.Initialize] 5EB044
[Vcl.表格][Vcl][Vcl.Forms.Tapplication.Run] 62573A
[最小模板.dpr][最小模板][最小模板.最小模板][注二十六]

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

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

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

内存在此代码中从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;   

显然,这需要向内河码头报告。我建议您提交错误报告。


解决此问题的另一种方法是尝试完全避免执行虚假行。我相信,如果您从 .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

相关内容

  • 没有找到相关文章

最新更新