为什么要使用“菜单”?单位确定得太早了吗?
我在打开 FastMM 和 FullDebugMode 的情况下测试了我的应用程序,因为我遇到了一些关闭问题。
在解决了我自己的一堆问题后,FastMM 开始抱怨在 TPopupList 中的已释放对象上调用虚拟方法。我尝试在使用中尽早移动菜单单元,以便最后完成,但这没有帮助。这是真正的问题吗?vcl 中的错误还是 FastMM 的误报?
以下是 FastMM 的完整报告:
FastMM has detected an attempt to call a virtual method on a freed object. An access violation will now be raised in order to abort the current operation.
Freed object class: TPopupList
Virtual method: Offset +16
Virtual method address: 4714E4
The allocation number was: 220
The object was allocated by thread 0x1CC0, and the stack trace (return addresses) at the time was:
403216 [sys\system.pas][System][System.@GetMem][2654]
404A4F [sys\system.pas][System][System.TObject.NewInstance][8807]
404E16 [sys\system.pas][System][System.@ClassCreate][9472]
404A84 [sys\system.pas][System][System.TObject.Create][8822]
7F2602 [Menus.pas][Menus][Menus.Menus][4223]
40570F [sys\system.pas][System][System.InitUnits][11397]
405777 [sys\system.pas][System][System.@StartExe][11462]
40844F [SysInit.pas][SysInit][SysInit.@InitExe][663]
7F6368 [PCCSServer.dpr][PCCSServer][PCCSServer.PCCSServer][148]
7C90DCBA [ZwSetInformationThread]
7C817077 [Unknown function at RegisterWaitForInputIdle]
The object was subsequently freed by thread 0x1CC0, and the stack trace (return addresses) at the time was:
403232 [sys\system.pas][System][System.@FreeMem][2699]
404A6D [sys\system.pas][System][System.TObject.FreeInstance][8813]
404E61 [sys\system.pas][System][System.@ClassDestroy][9513]
428D15 [common\Classes.pas][Classes][Classes.TList.Destroy][2914]
404AB3 [sys\system.pas][System][System.TObject.Free][8832]
472091 [Menus.pas][Menus][Menus.Finalization][4228]
4056A7 [sys\system.pas][System][System.FinalizeUnits][11256]
4056BF [sys\system.pas][System][System.FinalizeUnits][11261]
7C9032A8 [RtlConvertUlongToLargeInteger]
7C90327A [RtlConvertUlongToLargeInteger]
7C92AA0F [Unknown function at towlower]
The current thread ID is 0x1CC0, and the stack trace (return addresses) leading to this error is:
4714B8 [Menus.pas][Menus][Menus.TPopupList.MainWndProc][3779]
435BB2 [common\Classes.pas][Classes][Classes.StdWndProc][11583]
7E418734 [Unknown function at GetDC]
7E418816 [Unknown function at GetDC]
7E428EA0 [Unknown function at DefWindowProcW]
7E428EEC [Unknown function at DefWindowProcW]
7C90E473 [KiUserCallbackDispatcher]
7E42B1A8 [DestroyWindow]
47CE31 [Controls.pas][Controls][Controls.TWinControl.DestroyWindowHandle][6857]
493BE4 [Forms.pas][Forms][Forms.TCustomForm.DestroyWindowHandle][4564]
4906D9 [Forms.pas][Forms][Forms.TCustomForm.Destroy][2929]
Current memory dump of 256 bytes starting at pointer address 7FF9CFF0:
2C FE 82 00 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 C4 A3 2D 0C 00 00 00 00 B1 D0 F9 7F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0 00 00 00 16 32 40 00 9D 5B 40 00 C8 5B 40 00
CE 82 40 00 3C 40 91 7C B0 B1 94 7C 0A 77 92 7C 84 77 92 7C 7C F0 96 7C 94 B3 94 7C 84 77 92 7C
C0 1C 00 00 32 32 40 00 12 5B 40 00 EF 69 40 00 BA 20 47 00 A7 56 40 00 BF 56 40 00 A8 32 90 7C
7A 32 90 7C 0F AA 92 7C 0A 77 92 7C 84 77 92 7C C0 1C 00 00 0E 00 00 00 00 00 00 00 C7 35 65 59
2C FE 82 00 80 80 80 80 80 80 80 80 80 80 38 CA 9A A6 80 80 80 80 80 80 00 00 00 00 51 D1 F9 7F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C1 00 00 00 16 32 40 00 9D 5B 40 00 C8 5B 40 00
CE 82 40 00 3C 40 91 7C B0 B1 94 7C 0A 77 92 7C 84 77 92 7C 7C F0 96 7C 94 B3 94 7C 84 77 92 7C
, þ ‚ . € € € € € € € € € € € € € € € € Ä £ - . . . . . ± Ð ù
. . . . . . . . . . . . . . . . À . . . . 2 @ . [ @ . È [ @ .
Î ‚ @ . < @ ‘ | ° ± ” | . w ’ | „ w ’ | | ð – | ” ³ ” | „ w ’ |
À . . . 2 2 @ . . [ @ . ï i @ . º G . § V @ . ¿ V @ . ¨ 2 |
z 2 | . ª ’ | . w ’ | „ w ’ | À . . . . . . . . . . . Ç 5 e Y
, þ ‚ . € € € € € € € € € € 8 Ê š ¦ € € € € € € . . . . Q Ñ ù
. . . . . . . . . . . . . . . . Á . . . . 2 @ . [ @ . È [ @ .
Î ‚ @ . < @ ‘ | ° ± ” | . w ’ | „ w ’ | | ð – | ” ³ ” | „ w ’ |
我正在使用 Delphi 2007 和 FastMM 4.97。
Edit1:我认为这里的主要问题是为什么Classes.StdWndProc调用Menus.TPopupList?挖掘调试器内的调用堆栈显示 System.FinalizeUnit 被调用了 3 次,然后转到 SysUtils.ShowException,它尝试显示 MessageBox,在一堆 user32.dll 调用之后,我们最终到达了 classes.StdWndProc。
编辑2:我遇到了接口问题,修复后问题就消失了。带接口的对象被释放,但引用稍后被释放。当接口发布时,发生了一个异常,我最初以某种方式忽略了该异常。释放接口可能会损坏某些东西,从而导致所有其他问题。
I tested my application with FastMM and FullDebugMode turned on, since I had some shutdown problems.
After solving bunch of my own problems FastMM started to complain about calling virtual method on a freed object in TPopupList. I tried to move the menus unit as early as possible in uses so that it would be finalized last, but it didn't help. Is this real problem, a bug in vcl or false alarm from FastMM?
Here's the full report from FastMM:
FastMM has detected an attempt to call a virtual method on a freed object. An access violation will now be raised in order to abort the current operation.
Freed object class: TPopupList
Virtual method: Offset +16
Virtual method address: 4714E4
The allocation number was: 220
The object was allocated by thread 0x1CC0, and the stack trace (return addresses) at the time was:
403216 [sys\system.pas][System][System.@GetMem][2654]
404A4F [sys\system.pas][System][System.TObject.NewInstance][8807]
404E16 [sys\system.pas][System][System.@ClassCreate][9472]
404A84 [sys\system.pas][System][System.TObject.Create][8822]
7F2602 [Menus.pas][Menus][Menus.Menus][4223]
40570F [sys\system.pas][System][System.InitUnits][11397]
405777 [sys\system.pas][System][System.@StartExe][11462]
40844F [SysInit.pas][SysInit][SysInit.@InitExe][663]
7F6368 [PCCSServer.dpr][PCCSServer][PCCSServer.PCCSServer][148]
7C90DCBA [ZwSetInformationThread]
7C817077 [Unknown function at RegisterWaitForInputIdle]
The object was subsequently freed by thread 0x1CC0, and the stack trace (return addresses) at the time was:
403232 [sys\system.pas][System][System.@FreeMem][2699]
404A6D [sys\system.pas][System][System.TObject.FreeInstance][8813]
404E61 [sys\system.pas][System][System.@ClassDestroy][9513]
428D15 [common\Classes.pas][Classes][Classes.TList.Destroy][2914]
404AB3 [sys\system.pas][System][System.TObject.Free][8832]
472091 [Menus.pas][Menus][Menus.Finalization][4228]
4056A7 [sys\system.pas][System][System.FinalizeUnits][11256]
4056BF [sys\system.pas][System][System.FinalizeUnits][11261]
7C9032A8 [RtlConvertUlongToLargeInteger]
7C90327A [RtlConvertUlongToLargeInteger]
7C92AA0F [Unknown function at towlower]
The current thread ID is 0x1CC0, and the stack trace (return addresses) leading to this error is:
4714B8 [Menus.pas][Menus][Menus.TPopupList.MainWndProc][3779]
435BB2 [common\Classes.pas][Classes][Classes.StdWndProc][11583]
7E418734 [Unknown function at GetDC]
7E418816 [Unknown function at GetDC]
7E428EA0 [Unknown function at DefWindowProcW]
7E428EEC [Unknown function at DefWindowProcW]
7C90E473 [KiUserCallbackDispatcher]
7E42B1A8 [DestroyWindow]
47CE31 [Controls.pas][Controls][Controls.TWinControl.DestroyWindowHandle][6857]
493BE4 [Forms.pas][Forms][Forms.TCustomForm.DestroyWindowHandle][4564]
4906D9 [Forms.pas][Forms][Forms.TCustomForm.Destroy][2929]
Current memory dump of 256 bytes starting at pointer address 7FF9CFF0:
2C FE 82 00 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 C4 A3 2D 0C 00 00 00 00 B1 D0 F9 7F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0 00 00 00 16 32 40 00 9D 5B 40 00 C8 5B 40 00
CE 82 40 00 3C 40 91 7C B0 B1 94 7C 0A 77 92 7C 84 77 92 7C 7C F0 96 7C 94 B3 94 7C 84 77 92 7C
C0 1C 00 00 32 32 40 00 12 5B 40 00 EF 69 40 00 BA 20 47 00 A7 56 40 00 BF 56 40 00 A8 32 90 7C
7A 32 90 7C 0F AA 92 7C 0A 77 92 7C 84 77 92 7C C0 1C 00 00 0E 00 00 00 00 00 00 00 C7 35 65 59
2C FE 82 00 80 80 80 80 80 80 80 80 80 80 38 CA 9A A6 80 80 80 80 80 80 00 00 00 00 51 D1 F9 7F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C1 00 00 00 16 32 40 00 9D 5B 40 00 C8 5B 40 00
CE 82 40 00 3C 40 91 7C B0 B1 94 7C 0A 77 92 7C 84 77 92 7C 7C F0 96 7C 94 B3 94 7C 84 77 92 7C
, þ ‚ . € € € € € € € € € € € € € € € € Ä £ - . . . . . ± Ð ù
. . . . . . . . . . . . . . . . À . . . . 2 @ . [ @ . È [ @ .
Î ‚ @ . < @ ‘ | ° ± ” | . w ’ | „ w ’ | | ð – | ” ³ ” | „ w ’ |
À . . . 2 2 @ . . [ @ . ï i @ . º G . § V @ . ¿ V @ . ¨ 2 |
z 2 | . ª ’ | . w ’ | „ w ’ | À . . . . . . . . . . . Ç 5 e Y
, þ ‚ . € € € € € € € € € € 8 Ê š ¦ € € € € € € . . . . Q Ñ ù
. . . . . . . . . . . . . . . . Á . . . . 2 @ . [ @ . È [ @ .
Î ‚ @ . < @ ‘ | ° ± ” | . w ’ | „ w ’ | | ð – | ” ³ ” | „ w ’ |
I'm using Delphi 2007 and FastMM 4.97.
Edit1: I think the main problem here is why does Classes.StdWndProc call Menus.TPopupList? Digging the call stack inside debugger shows that System.FinalizeUnit is called three times, then it goes to SysUtils.ShowException, which tries to display MessageBox and after bunch of user32.dll calls we end up to classes.StdWndProc.
Edit2: I had problem with interfaces, fixing that made this problem go away. The object with interface was freed, but the reference was released later on. When the interface was released, occured an exception which I initially somehow ignored. Releasing the interface probably corrupted something which caused all other problems.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当一个单元在它间接依赖的另一个单元之后完成时,就会发生这种情况。
例如,采用以下单位:
该单位仅直接依赖于 Contnrs。因此,delphi 将确保该单元在 Contnrs 之前完成。如果ObjectList包含TForms,Delphi将不会确保Unit1在单元Forms之前完成。如果关闭应用程序时仍有一些表单剩余,TObjectList(因为它拥有该对象)将释放它包含的项目(调用 TForm.Free)。但由于 Unit1 不依赖于 TForm,因此单元 Forms 可能已经最终确定,并且 TForm.Destroy 不再位于内存中。
这就是为什么您需要非常小心在最终确定部分所做的事情。
我不确定这是你问题的根源,但我会先看看这个。
That situation can happens when a unit finalize after another unit it indirectly depends on.
For exemple, take the following unit:
That unit only directly depends on Contnrs. For that reason, delphi will ensure that this unit is finalized before Contnrs is. If the ObjectList contains TForms, Delphi won't ensure that Unit1 is finalized before unit Forms. If there are still some forms left while closing the application, TObjectList (Since it owns the object) will free the items it contains(Call TForm.Free). But since Unit1 doesn't depends on TForm, it's possible that the unit Forms is already finalized and that TForm.Destroy isn't in memory anymore.
This is why you need to be very carefull about what you do in finalization sections.
I'm not sure it's the source of your problem, but I would look that way first.
我以前在 Delphi 2007 中也见过这样的问题。有时,编译器会感到困惑并生成不正确的初始化或终结顺序。遗憾的是,我始终无法创建可复制的测试用例来发送给 CodeGear/Embarcadero 人员。
每当这种情况发生时,全面重建就会有所帮助。
I've seen such problems with Delphi 2007 before. Sometimes the compiler gets confused and generates incorrect initialization or finalization order. Sadly, I was never able to create a reproducible test case to send to the CodeGear/Embarcadero people.
Whenever that happened, a full rebuild helped.
确保 FastMM4 是项目文件的使用子句中的第一行(项目|查看源代码)。如果不存在,则添加它。
Make sure that FastMM4 is the FIRST line in your project file's uses clause (project|View source). If its not there, then add it.
看起来您的其中一个表单在 Menus.pas 完成后被销毁。如果您的表单上有菜单,则它的界面部分的使用列表中可能必须有菜单,这应该使这成为不可能。
我唯一一次看到像这样弹出的问题(没有双关语)是在使用包时。您是否可能使用带有插件的 DPK 来向您的程序添加弹出菜单或菜单项?如果您不小心,包终结可能会给您的程序带来一些奇怪的事情。
不管怎样,解决方案可能是在 menus.pas 最终确定之前自行处理菜单。当程序需要关闭时,在弹出菜单上调用“Free”,看看是否可以解决问题。
It looks like one of your forms is getting destroyed after Menus.pas has been finalized. If your form has a menu on it, it would probably have to have Menus in its uses list in the interface section, which should make this impossible.
The only time I've seen issues like this pop up (no pun intended) is when using packages. Are you perhaps using a DPK with a plugin that adds a popup menu or menu items to your program? Package finalization can do some strange things to your program if you're not careful.
Either way, the solution is probably to dispose of the menu yourself before menus.pas finalizes. When it's time for the program to shut down, call Free on your popup menu and see if that solves the problem.
更新:这只是部分解决方法
解决方法:
在应用程序的主窗体中编写
这个免费的 PopupList 并设置为 nil,这样在 menus.pas 中的 PopupList.Free 就可以了。
Update: this is only partial workaround
Workaround:
In main form of your application write
this free PopupList and set to nil, so PopupList.Free in menus.pas will be OK.