简体   繁体   English

Delphi窗体控件上的内存泄漏

[英]Memory Leak on Delphi Form Controlls

I've found a strange memory leak in a project that I've been newly assigned to. 我在新分配给的项目中发现了一个奇怪的内存泄漏。

On terminating, the program displays the following FastMM4 error message. 终止时,程序将显示以下FastMM4错误消息。

FastMM4错误

The project uses BusinessSkinForm 该项目使用BusinessSkinForm

TbsaSpeedButtonSubClass is from the third party BusinessSkinForm library, however the speed buttons on that form appear to be regular VCL form controls. TbsaSpeedButtonSubClass来自第三方BusinessSkinForm库,但是该表单上的速度按钮似乎是常规的VCL表单控件。

When I add another speed button to the form, 当我在表单中添加另一个速度按钮时,

speedButton

I now have 25 instances of TbsaSpeedButtonSubClass that leak instead of 24. 我现在有25TbsaSpeedButtonSubClass实例,而不是24个实例。

Which leads me to think that the leak is due to the TSpeedButton . 这使我认为泄漏是由于TSpeedButton However, this seems strange to me since I would expect form components to be automatically freed by the form upon destruction. 但是,这对我来说似乎很奇怪,因为我希望表单组件在销毁后会自动释放。

Perhaps BusinessSkinForm does something unusual to the form which results in a leak... 也许BusinessSkinForm对表单做一些不寻常的事情,导致泄漏...

I'm not sure how to get rid of this leak 我不确定如何摆脱这种泄漏

EDIT 编辑

Thanks to KenWhite I have a memory leak report from FastMM4 感谢KenWhite,我收到了FastMM4的内存泄漏报告

Here it is on Pastebin 这是在Pastebin上

EDIT 编辑

As shown in the stack trace, the problem can be traced to a TMUSICMainForm.SkinForm_OnCreate(SkinForm: TForm); 如堆栈跟踪所示,该问题可以追溯到TMUSICMainForm.SkinForm_OnCreate(SkinForm: TForm);

The problem seems to be related to a BSA: TbsaSkinAdapter 该问题似乎与BSA: TbsaSkinAdapter

If I comment out the line BSA.ChangeSkinData; 如果我将BSA.ChangeSkinData;BSA.ChangeSkinData;

the leak is no longer present. 泄漏不再存在。

EDIT 编辑

Here is the important part of the stack trace 这是堆栈跟踪的重要部分

--------------------------------2015/11/24 12:16:03-------------------------------- A memory block has been leaked. -------------------------------- 2015/11/24 12:16:03 -------- ------------------------内存块已泄漏。 The size is: 308 大小是:308

This block was allocated by thread 0x1258, and the stack trace (return addresses) at the time was: 402AB6 [madZip][madZip][@GetMem] 4035F9 [madCrypt][madCrypt][TObject.NewInstance] 4039CA [madCrypt][madCrypt][@ClassCreate] 67438A [bsaadapter.pas][bsaadapter][TbsaSpeedButtonSubclass.Create][11537] 66137E [bsaadapter.pas][bsaadapter][TbsaHook.SetControl][2637] 403A1E [madCrypt][madCrypt][@AfterConstruction] 665BFB [bsaadapter.pas][bsaadapter][TbsaSkinManager.DoControlMessage][4898] 6615B7 [bsaadapter.pas][bsaadapter][TbsaHookCollection.AddControl][2760] 404ACB [madExcept][madExcept][@LStrSetLength] 662A0E [bsaadapter.pas][bsaadapter][TbsaSkinManager.CollectSpeedButton][3544] 92C81D [Sources\\uMainForm.pas][uMainForm][TMUSICMainForm.SkinForm_OnCreate][4778] 该块由线程0x1258分配,当时的堆栈跟踪(返回地址)为:402AB6 [madZip] [madZip] [@ GetMem] 4035F9 [madCrypt] [madCrypt] [TObject.NewInstance] 4039CA [madCrypt] [madCrypt ] [@ ClassCreate] 67438A [bsaadapter.pas] [bsaadapter] [TbsaSpeedButtonSubclass.Create] [11537] 66137E [bsaadapter.pas] [bsaadapter] [TbsaHook.SetControl] [2637] 403A1E [madCrypt] [madCrypt] [@ AfterConstruction] 665BFB [bsaadapter.pas] [bsaadapter] [TbsaSkinManager.DoControlMessage] [4898] 6615B7 [bsaadapter.pas] [bsaadapter] [TbsaHookCollection.AddControl] [2760] 404ACB [madExcept] [madExcept] [@ LStrSetLerthE] ] [bsaadapter] [TbsaSkinManager.CollectSpeedButton] [3544] 92C81D [Sources \\ uMainForm.pas] [uMainForm] [TMUSICMainForm.SkinForm_OnCreate] [4778]

The block is currently used for an object of class: TbsaSpeedButtonSubclass 该块当前用于以下类的对象:TbsaSpeedButtonSubclass

The allocation number is: 475863 分配编号是:475863

Current memory dump of 256 bytes starting at pointer address 7E8A7670: 64 C9 65 00 00 00 00 00 00 00 00 00 00 00 00 00 68 F3 48 00 50 96 97 7E B8 5E 74 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B8 D1 74 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 d É e . 从指针地址7E8A7670开始的256个字节的当前内存转储:64 C9 65 00 00 00 00 00 00 00 00 00 00 00 00 00 68 F3 48 00 50 96 97 7E B8 5E 74 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B8 D1 74 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 dée . . . . . . . . . . . . h ó H . H 2 O 2小时。 P – — ~ ¸ ^ t ~ . P – —〜¸^ t〜。 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ¸ Ñ t ~ . tÑt〜。 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

EDIT 编辑

I've managed to create a minimum working example of the memory leak. 我设法创建了一个内存泄漏的最小工作示例。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  BusinessSkinForm, bsaadapter, Buttons
  ;

type
  TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
  BSF: TbsBusinessSkinForm;
  BSA: TbsaSkinAdapter;
begin
    BSF := TbsBusinessSkinForm.Create(Self);

    BSF.BorderIcons:=[biMinimize,biMaximize];

    BSA := TbsaSkinAdapter.Create(Self);

    BSA.AdapterType := bsaUseClasses;

    BSA.ChangeSkinData;
end;

end.

I've found that even if I comment out seemingly innocent looking lines like BSF.BorderIcons:=[biMinimize,biMaximize]; 我发现即使我注释掉了看起来像BSF.BorderIcons:=[biMinimize,biMaximize];无害外观的行BSF.BorderIcons:=[biMinimize,biMaximize]; or BSA.AdapterType := bsaUseClasses; BSA.AdapterType := bsaUseClasses; then the memory leak disappears. 然后内存泄漏消失了。

Note my delphi form in this example contains 1 TSpeedButton 请注意,本例中我的delphi表单包含1个TSpeedButton

最小的错误

EDIT 编辑

I should also add that I'm using windows 7 (64bit), 6GB ram, delphi 5, Business Skin version 4.70 我还应该补充一点,我正在使用Windows 7(64位),6GB内存,delphi 5,Business Skin版本4.70

EDIT 编辑

the bsaadapter unit in BusinessSkinForm contains a function BusinessSkinForm中的bsaadapter单元包含一个函数

procedure TbsaSkinManager.DoUnhook(Control: TControl; Handle: HWnd);
var
  i: integer;
  SC: TbsaSubclass;
  R: TRect;
begin
  if FUnhooking then Exit;

  if FUnhookedList = nil then
  begin
    FUnhooking := true;
    Exit;
  end;

  FUnhooking := true;
  try
    for i := FHandleList.Count - 1 downto 0 do
    begin
      SC := TbsaSubclass(FHandleList[i]);

      if (Handle <> 0) and (SC.Handle = Handle) then
      begin
        R := Rect(0, 0, 2000, 2000);
        PostMessage(Handle, WM_NCPAINT, 0, 0);
        InvalidateRect(Handle, @R, false);
        FHandleList.Delete(i);
        SC.Free;
      end;

      if (Control <> nil) and (SC.Control = Control) then
      begin
        FHandleList.Delete(i);
        SC.FControl := nil;
        if not (Control is TGraphicControl) then
          SC.Free;
      end;
    end;
  finally
    FUnhooking := false;
  end;
end;

It seems that speed buttons do not get freed because they are instances of TGraphicControl 似乎速度按钮没有被释放,因为它们是TGraphicControl实例

if not (Control is TGraphicControl) then SC.Free; 如果不是(Control是TGraphicControl),则SC.Free;

While a regular TButton will get freed 虽然常规的TButton将被释放

From what I can see here there are a number of ways which I can proceed from here. 从这里我可以看到,有很多方法可以从这里开始。

  1. Submit a fix to BusinessSkinForm to handle the speed button 将修订提交给BusinessSkinForm以处理速度按钮

  2. Live with using a work around ie: BSA.AdapterType := bsaUseNames; 可以使用以下解决方法: BSA.AdapterType := bsaUseNames; instead of BSA.AdapterType := bsaUseClasses; 而不是BSA.AdapterType := bsaUseClasses;

  3. Replace the speed buttons with the regular TButton . 将速度按钮替换为常规的TButton

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM