Delphi应用在调试器外崩溃,但在调试器内不会。

4
我们的DUnit项目在退出时会崩溃。如果“无调试运行”,它就会崩溃,但是如果我在调试器中运行,它就不会崩溃。
如果我在启动进程后将调试器附加到进程上,则不会在退出时崩溃。
我怀疑是在最终化过程中出了问题,因此我在所有我怀疑正在运行的最终化代码中放置了打印语句。这没有发现任何有用的信息。一个我们低级别单元(不依赖于任何非系统单元)的最终化正在正确运行。因此,仍然可能是最终化问题,但也可能不是。
崩溃会产生此对话框:
Problem signature:
  Problem Event Name:   APPCRASH
  Application Name: MCLTesting.exe
  Application Version:  0.0.0.0
  Application Timestamp:    4eb07b50
  Fault Module Name:    kernel32.dll
  Fault Module Version: 6.0.6001.18215
  Fault Module Timestamp:   49953395
  Exception Code:   c0000005
  Exception Offset: 000bf395
  OS Version:   6.0.6001.2.1.0.256.6
  Locale ID:    3081
  Additional Information 1: b37c
  Additional Information 2: 2a7328d8bb40c81c93b4b5f46adb8e10
  Additional Information 3: b37c
  Additional Information 4: 2a7328d8bb40c81c93b4b5f46adb8e10

"异常代码:c0000005" 这是什么意思?

我唯一的线索就是它在调试器中没有崩溃。有人之前见过类似情况吗?


1
异常0xC0000005表示应用程序访问了它不拥有的内存。例如,尝试读取超出分配缓冲区末尾的内容可能会导致此问题。在调试器的上下文中运行时,内存布局可能会发生变化,理论缓冲区后面的内存仍然属于该进程。 - Mark Wilkins
3
这通常是在Delphi运行库异常处理程序卸载后发生的异常情况;错误0xC0000005STATUS_ACCESS_VIOLATION。这也可能是违反数据执行预防(DEP)导致的错误。MadExcept可能能够帮助跟踪它。它是免费供非商业使用(如果您可以在最终用户应用程序中使用它,则绝对值得购买),因此您可以将其用于调试此类问题。 - Ken White
2
如果没有其他方法可行,尝试逐步注释掉代码的一部分,以便找出导致崩溃的部分。这是“穷人调试器”,在任何时候和任何地方都有效。但是,对于死锁、竞争条件或其他线程同步错误则无效。 - Serhii Kheilyk
@Sergiy,你的建议最终起作用了。 - awmross
酷。顺便问一下,真正的原因是什么? - Serhii Kheilyk
显示剩余2条评论
2个回答

4

我终于找到了问题所在。

问题确实出现在终结器中。在终结器中抛出了一个用户异常。异常未被捕获,异常本身被泄漏(异常及其字符串未被释放)。似乎这个内存泄漏导致了崩溃?我不确定为什么我最初发布时没有注意到这个内存泄漏。

捕获异常解决了崩溃问题。

我发现的一个有趣的事情是,即使在终结器中抛出未捕获的异常,后续的Unit终结器仍然会运行。我原以为一个终结器中的问题会阻止所有后续终结器的运行。

我用来找到有问题的Unit的方法非常简单:我从项目中删除了所有Unit,然后逐个重新引入Unit,直到发现崩溃错误。虽然耗费时间,但最终还是解决了问题。


2

异常代码c0000005是一种访问冲突。通常情况下,这意味着以下两种情况之一:要么您正在尝试解引用一个设置为nil的指针或对象引用,要么您正在使用已损坏的内存。

错误报告中的另一个相关数据是Exception Offset: 000bf395。这告诉您错误发生的位置。尝试在您的映射文件中查找f395,看看是否可以找到与该内存偏移相对应的单元完成。如果是这样,那么这应该能够给您一个很好的想法,出了什么问题。


“f395” 的唯一出现是在一个名为“Line numbers for Controls(Controls.pas) segment .text”的部分中。我认为这与有问题的单元无关?(请参见我的回答) - awmross

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接