[英]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错误消息。
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, 当我在表单中添加另一个速度按钮时,
I now have 25 instances of TbsaSpeedButtonSubClass
that leak instead of 24. 我现在有25个
TbsaSpeedButtonSubClass
实例,而不是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. 从这里我可以看到,有很多方法可以从这里开始。
Submit a fix to BusinessSkinForm to handle the speed button 将修订提交给BusinessSkinForm以处理速度按钮
Live with using a work around ie: BSA.AdapterType := bsaUseNames;
可以使用以下解决方法:
BSA.AdapterType := bsaUseNames;
instead of BSA.AdapterType := bsaUseClasses;
而不是
BSA.AdapterType := bsaUseClasses;
Replace the speed buttons with the regular TButton
. 将速度按钮替换为常规的
TButton
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.