2

我有一个奇怪的错误,当删除一个特定对象时,delete永远不会返回。相反,它似乎花时间Sleep()在一个永久循环中调用。这是调用堆栈:

:7723fd71 ntdll.ZwDelayExecution + 0x15
:767c4498 KERNELBASE.Sleep + 0xf
:21495359 BORLNDMM.@Borlndmm@SysFreeMem$qqrpv + 0xb5
:32aaa3e5 CC32100MT._free + 0xd
:32a020b2 CC32100MT.@$bdele$qpv + 0x1e
[My code]

运行时,它返回SysFreeMem(从不返回)并再次从内部free调用,永久循环。SleepSysFreeMem

我的代码非常简单:它是一个 VCL 事件处理程序,一个微调框刚刚更改,一个设置对象更新,并且它所做的临时设置正在被删除:

delete poNewSettings;

这段代码一两年没有改变,设置类也有一段时间没有改变,它基本上是一个包含许多设置的巨大的类似结构的对象。它有一个编译器生成的析构函数。单步执行代码显示了一些删除字符串和其他 std:: 对象的调用,然后在单步执行下一个函数(即在 IDE结束时~basic_string(),在右大括号处按 F7 )时,它似乎冻结了}从不显示。冻结是它在 Sleep() 中。此代码在主线程中运行。

我尝试使用 CPU 视图来推断调用 Sleep() 的延迟,但无法发现它 - 恐怕我还没有完全掌握 x86 汇编代码。

另一个线程在里面Sleep,可能与 COM 相关(该应用程序是一个 COM 服务器,尽管目前没有使用 COM)。它的整个调用栈是:

:7723fd71 ntdll.ZwDelayExecution + 0x15
:767c4498 KERNELBASE.Sleep + 0xf
:74c7d98d ; C:\Windows\syswow64\ole32.dll
:74c7d87a ; C:\Windows\syswow64\ole32.dll
:768133aa kernel32.BaseThreadInitThunk + 0x12
:77259ef2 ntdll.RtlInitializeExceptionChain + 0x63
:77259ec5 ntdll.RtlInitializeExceptionChain + 0x36

另一个线程正在做某事并主动分配和释放内存并调用Sleep()- 一个后台任务正在运行,它正在检查它是否需要工作(它不必)并且正在休眠 100 毫秒以再次检查。分配和免费用于文件夹路径的字符串。虽然程序中还有其他线程,但它们都被阻塞等待做某事,这次使用WaitForSingleObject或类似的。此后台任务线程每 100 毫秒唤醒一次(从睡眠中返回);我没有看到(还没有!)它如何影响另一个线程的delete.

据我所知,没有其他线程正在删除或分配任何东西。CC32100MT._malloc我在,CC32100MT._free和中放置了断点CC32100MT._realloc。运行时没有其他线程中断,当暂停检查时,没有其他线程在任何这些调用中。

删除循环而不返回的原因可能是什么?

我正在使用: * RAD Studio 2010,完全更新 * 应用程序主要是 C++(C++ Builder),带有少量 Delphi。* 因为它使用的是 Embarcadero RTL,所以我认为它使用的是 FastMM

我添加了 Delphi 标签,因为它使用 Embarcadero RTL 和 FastMM,Delphi 人使用的次数比 C++ 人多得多。

4

1 回答 1

0

在这种情况下,我不能 100% 确定您是否可以信任 RAD Studio IDE 中的调试器来正确命名所涉及的内核符号。

我认为您应该进入发生这种情况的地方,然后检查您正在释放的变量,看看它是否已损坏。

如果您要释放的变量是您自己定义的类,我通常喜欢将 Guard 字段添加到对象的开头和结尾。

class TMyPOSettings {
  public:
    ...
  private:
    int Guard1;
    // all my other instance data 
    int Guard2
};

在构造函数中,我将守卫设置为我在某处定义的 MAGIC1 和 MAGIC2,在析构函数中,我将守卫设置为 MAGIC_FREE_1 和 MAGIC_FREE_2。

然后我可以查看我是否重复破坏了同一个对象,或者是否有其他东西覆盖了我在该位置的堆内存。

我想知道您正在调试的内容是否可能实际上是在 Windows 中捕获到严重异常后代码的结果,中止您的线程正在执行的任何操作,并且基本上现在什么都不做,直到您的进程终止。我要调试的第一个地方是单步执行析构函数的代码并查看它的作用。

于 2013-03-08T22:42:51.300 回答