调试访问冲突错误?

21 delphi access-violation

在Delphi中编写应用程序时,您可以分享哪些提示来帮助查找和修复访问冲突?

我认为访问冲突通常是由于尝试访问尚未创建的内存中的某些内容(例如Object等)引起的?

我发现很难确定是什么触发了访问冲突,然后在哪里进行必要的更改以尝试停止/修复它们.

一个例子是我正在进行的个人项目.我在TTreeView Node.Data属性中存储了每个节点的一些数据.节点可以多次选择和导出(导出遍历每个选定节点并将特定数据保存到文本文件 - 保存到文本文件的信息是存储在nodes.data中的信息).文件也可以导入Treeview(将文本文件的内容保存到node.data中).

该示例中的问题是,如果我将文件导入Treeview然后导出它们,它就完美了.但是,如果我在运行时添加一个节点并导出它们,我得到:

"模块'Project1.exe'中地址00405772的访问冲突.读取地址00000388."

我对此的想法必须是我将数据分配给创建节点的方式,可能与导入时分配数据的方式不同,但这对我来说都很好.访问冲突仅在导出时显示,导入的文件不会发生这种情况.

我不是在寻找上述示例的修复程序,但主要是建议/提示如何查找和修复此类错误.我经常不会违反访问权限,但是当我这样做时,他们很难找到并修复.

所以建议和提示非常有用.

Lar*_*ens 24

这意味着您的代码正在访问不允许的内存的某些部分.这通常意味着您有一个指向错误内存的指针或对象引用.也许是因为它没有初始化或已经发布.

使用调试器,如Delphi.它将告诉您AV发生的代码行.从那里通过查看callstack和局部变量等来找出问题.有时,如果使用Debug DCU进行编译,它也会有所帮助.

如果您没有调试器,因为它只发生在客户端,您可能希望使用MadExcept或JclDebug使用callstack记录异常并将其发送给您.它可以为您提供更少的细节,但可能会指向您正确的方向.

通过更积极地检查,有些工具可能能够更早地找到这些问题.FastMM内存管理器有这样的选项.

编辑

"模块'Project1.exe'中地址00405772的访问冲突.读取地址00000388."

因此,您的问题导致模块"Project1.exe"中的地址为00405772的AV.Delphi调试器将带您到正确的代码行(或使用查找错误).

它试图读取地址00000388处的内存.这非常接近00000000(nil),因此这可能意味着访问一些指向数组的指针/引用或nil的动态数组.如果它是一个字节数组,它将是项目388.或者它可能是一个相当大的对象或具有大量字段的记录的字段.对象或记录指针/引用将为零.

  • +1用于巧妙地指出空页面:) (6认同)

War*_* P 18

我发现当我在调试器中运行时,并不总是会发生真正难以发现的访问冲突.更糟糕的是,它们发生在顾客而不是我身上.接受的答案提到了这一点,但我真的认为它应该被赋予更多的细节:MadExcept提供了一个堆栈回溯,它给了我有价值的上下文信息,并帮助我查看代码失败的地方,或者有未处理的异常(它不仅仅是访问违规).它甚至为客户提供了一种方法,可以直接通过电子邮件向您发送错误报告.这会导致您的Beta测试人员或您的用户报告发现并修复了更多访问冲突.

其次,我注意到编译器提示和警告实际上正在检测一些常见问题.清理提示和警告,您可能会发现许多访问冲突和其他微妙问题.例如,忘记正确声明析构函数可能会导致编译器警告,但会导致运行时出现严重问题.

第三,我发现Peganza的Pascal Analyzer等工具,以及某些版本的Delphi中的审计和度量功能,可以帮助您找到有问题的代码区域.作为一个具体的例子,Pascal Analyzer找到了我忘记做重要事情的地方,这会导致崩溃或访问冲突.

第四,你很难打败让另一个开发者批评你的代码的技巧.之后你可能会感到有点羞怯,但是你会学到一些东西,希望能够更好地做你正在做的事情.有可能,使用树视图的方式多于一个,而且比你更多的方式来做你正在做的工作,更好的架构和干净的做事方式将导致更可靠的代码每次触摸它都不会破坏.这不是生成清洁代码的有限规则列表,而是一生的努力和程度问题.你会惊讶地看到无辜的代码可能成为潜在崩溃,访问违规,竞争条件,冻结和死锁的温床.

  • 这是非常真实的沃伦,谢谢你的提示. (2认同)
  • 感谢您将我们指向Pascal Analyzer - 他们现在拥有免费(Lite)版本...... (2认同)