2

我遇到了典型的访问冲突:

access violation at 0x4ebb7456: read of address 0x4ebb7456

这发生在当程序的其余部分已经关闭时创建的线程中。

发生异常时主线程正在运行System.FinalizeUnits

我发现该地址属于gdiplus.dll已加载的内存区域。

如果我添加LoadLibrary('gdiplus.dll')对 dpr 文件的调用而不调用FreeLibrary返回的句柄,问题就会消失,这样在gdiplus.dll运行终结部分时不会卸载。

如何找出程序的哪个部分创建了导致访问冲突的线程?

有没有办法识别调用释放内存空间的代码?

FastMM 和 madExcept 帮助不大,出现了 madExcept 错误报告窗口,但又立即关闭,不写入日志文件。

我可以将程序拆开,但它是一个不平凡的应用程序,我宁愿使用某种调试技术来解决这个问题。

4

2 回答 2

3

追踪这一点的第一步可能是检测代码的哪一部分实际创建了线程。在应用程序关闭期间创建线程对我来说听起来像是坏消息,所以我希望确保不会发生这种情况。

至于怎么做,我会使用调试器断点。首先,我会CreateThread在 Windows.pas 的实现上设置一个断点,并使用调试 DCU 运行。查看该断点是否在关机期间触发。

如果它在关机期间没有中断,那么该线程是由非 Delphi 代码创建的。我的下一步是打开 CPU 视图并进入CreateThread. 的反汇编CreateThread将从一条JMP指令开始。踏入这一步,你将在kernel32.CreateThread。现在在这里设置一个断点,看看在关闭期间触发它时调用堆栈是什么。

于 2011-08-01T14:33:05.537 回答
2

我会找到正在加载库的单元(可能是您正在使用的组件)并将其添加到项目文件的顶部(或顶部附近)。这将确保它在您的应用程序关闭后被卸载,并且应该阻止 AV。

因此,例如,如果您使用的是GdiPlus,您最终会得到这样的结果:

program MyProgram;

uses
  FastMM4,
  GdiPlus,  // <=== this line inserted
  Windows,
  Forms,
  Controls,
  Classes,

这可能会掩盖一个以后可能会再次困扰您的问题。值得尝试找出哪个单元正在尝试调用已卸载的 DLL 以及执行此操作。

于 2011-08-01T14:45:11.697 回答