【问题标题】:Invalid Pointer Operation - Delphi XE无效的指针操作 - Delphi XE
【发布时间】:2012-04-24 04:20:03
【问题描述】:

我似乎无法弄清楚这一点。我的程序编译并运行成功,但只有在调试过程中,它才会在关闭程序时弹出一个消息框,提示“指针操作无效”。我煞费苦心地检查了所有 FormCloseQuery 和 FormDestory 事件是否有任何语法或逻辑错误。我没有找到,它们按预期执行,没有任何错误。

当我告诉编译器在 Invalid Pointer Operation 错误时中断时,它什么也不做,只是挂起程序。此时,我不得不终止或终止该进程。

你是怎么解决这个问题的?

提前致谢,

【问题讨论】:

  • 启用调试 DCU 并逐步关闭,直到找到触发此错误的原因。您是否在完全调试模式下使用 FastMM 运行?
  • @DavidHeffernan, :) 我记得我们曾讨论过 FastMM。不幸的是,我没有使用过 FastMM,因为我在回来时测试过它。我将启用 DCU,看看会发生什么。
  • @DavidHeffernan,在启用 dcu 中断后,调试器在 System.pas 文件中停止。有点混乱,但我认为这是梅森惠勒的原因之一。我想现在我得把 FastMM 放回去了。
  • 设置一些堆栈跟踪器并可能转一圈“使用调试 DCU” 看起来您有一些您尝试释放两次的杂散指针。 stackoverflow.com/questions/3631987stackoverflow.com/questions/12505251stackoverflow.com/questions/2237028
  • 如果您“没有找到”,那么您需要更加努力地寻找,因为显然您的程序存在问题。

标签: delphi debugging exception delphi-xe


【解决方案1】:

内存管理器在尝试释放无效内存时会引发无效指针异常。这可以通过三种方式发生。

最常见的是因为您试图释放一个已经释放的对象。如果您打开 FastMM 的 FullDebugMode,它会检测到这一点并直接指出问题所在。 (但请确保构建一个映射文件,以便它拥有创建有用堆栈跟踪所需的信息。)

第二种方法是,如果您试图释放分配给内存管理器以外的其他地方的内存。在将 string 从 Delphi EXE 传递到不使用共享内存管理器功能的 Delphi DLL 时,我已经看到过几次。

第三种方法涉及直接使用指针,可能不适用于您。如果您尝试 FreeMemDispose 一个不指向 FastMM 分配的实际内存块的错误指针,您将收到此错误。

这很可能是第一个。使用FullDebugMode,你会很容易找到问题的根源。

【讨论】:

  • 你是绝对正确的。您的第一个原因是为什么我的程序会引发此异常通知。但是,它正在引发,因为我的 TForm 的破坏事件被多次调用。我不明白为什么。
  • 如果我猜测一下,我会说因为您的表单是由所有者创建的(例如应用程序;您是否使用Application.CreateForm 来构造它?)然后在其他地方您重新尝试手动释放它。查看两次释放的堆栈跟踪;他们会让你知道发生了什么。并牢记Single Ownership Principle:您的表单可以由应用程序或您的代码拥有,但不能由两者拥有。
【解决方案2】:

我在 Delphi 调试过程中被这种类型的“指示错误”发现了。

检查您是否有任何已启用“允许函数调用”的监视变量,或尝试在同一单元(或全局)中显示可能未初始化的其他变量的监视。当在断点处停止时,这可能会导致 Delphi 的调试器尝试通过访问未初始化的指针或变量的函数调用来显示值。导致 AV 的实际变量甚至不在你的观察名单上。

【讨论】:

  • EAccessViolation 与 EInvalidPointer 不同。 访问一个无效的指针给出前者;只有 释放 给后者。
【解决方案3】:

当您告诉 Delphi 内存管理器释放不属于它的内存时,会发生无效的指针操作。可能发生的三种方式:

  • 释放已释放的指针或对象。
  • 使用FreeMem 释放由其他内存管理器(例如GlobalAllocCoTaskMemAlloc)分配的内容。
  • 释放未初始化的指针。 (这与释放空指针不同,后者是完全安全的。)

在你的程序的某个地方,你正在做这些事情之一。调试器检测到内存管理器抛出的异常,所以做一些调试。从堆栈跟踪中,您应该能够看到您要释放的变量。检查程序的其余部分以了解该变量的其他使用方式。

MadExcept 和 Eureka Log 等工具可以帮助您找到双重释放错误。他们可以跟踪相关指针的分配位置和第一次释放的位置,这些信息有时足以找出您的错误并停止多次释放。

【讨论】:

  • 如果尝试释放本地声明对象的地址,是否也会抛出?
  • 是的,@Wolf。第二个要点涵盖了这一点。在这种情况下,您将尝试释放堆栈上分配的内存。
  • 谢谢。在谈论自动变量时,这种“分配”或“内存管理器”看起来很奇怪。也许这也应该添加(以更明确的方式)?
  • 我认为答案的第一句话很好地涵盖了所有内容,@Wolf。其余的答案只是详细说明。我不想详细列出所有内存分配方式,但不是主要的 Delphi 内存管理器。
  • 我明白了。我只是试图通过释放堆栈内存来引发该异常,但我无法做到。我唯一得到的工作是一个EAccessViolation,通过调用delete 指针变量,我通过reinterpret_cast 填充了int 值。
【解决方案4】:

可能发生无效指针操作的第四个原因。我有两个指针,其中数组 [0..1000] 为实数,第三个指针是数组 [1..200] 为实数。初始化的所有 3 个指针 对于 i := 0 到 1000 做 开始 ptr1^[i]:=0;ptr2^[i]:=0;ptr3^[i]:=0; 结尾; 虽然这种糟糕的编程并没有打扰 Delphi 中的 Pascal,但调用 Dispose 3 个指针中的任何一个都会导致无效的指针操作。修复只是正确初始化第三个指针。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 2011-05-25
    相关资源
    最近更新 更多