如何找出哪些代码调用已卸载的模块?

时间:2011-08-01 14:07:57

标签: delphi debugging delphi-2007 access-violation application-shutdown

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

access violation at 0x4ebb7456: read of address 0x4ebb7456

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

主要线程在异常时运行System.FinalizeUnits

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

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

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

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

FastMM和madExcept没什么帮助,madExcept错误报告窗口出现了,但是立即关闭并且不写日志文件。

我可以拆开程序,但这是一个非常简单的应用程序,我宁愿使用某种调试技术解决这个问题。

2 个答案:

答案 0 :(得分:3)

跟踪此问题的第一步可能是检测代码的哪个部分实际创建了该线程。在应用程序关闭期间创建一个线程听起来像是制作中的坏消息,因此我希望确保不会发生这种情况。

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

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

答案 1 :(得分:2)

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

因此,例如,如果您使用的是GdiPlus,那么您最终会得到类似的结果:

program MyProgram;

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

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