2

尝试删除它时出现分段错误。

我知道你想删除这个,但它是我的前任留下的。我知道我应该采取的一些预防措施,这些预防措施已经过验证和处理。

我不知道什么样的条件可能导致这次崩溃,只是偶尔一次。大约 95% 的时间代码运行得非常好,但有时这似乎以某种方式损坏并崩溃。

顺便说一句,类的析构函数没有做任何事情。

我是否应该假设某些东西正在其他地方破坏我的堆,并且 this 指针以某种方式搞砸了?

编辑:根据要求,崩溃代码:

long CImageBuffer::Release()
{
  long nRefCount = InterlockedDecrement(&m_nRefCount);
  if(nRefCount == 0)
  {
    delete this;
  }
  return nRefCount;
}

该对象是用新创建的,它不在任何类型的数组中。

4

3 回答 3

1

最明显的答案是:不要删除它。

如果您坚持这样做,请使用常见的查找错误的方法:
1. 使用 valgrind(或类似工具)查找内存访问问题
2. 编写单元测试
3. 使用调试器(准备长时间盯着屏幕 - 取决于如何你的项目很大)

于 2011-09-16T19:17:18.153 回答
1

好像你和 不new匹配delete。请注意,delete this;只能在使用分配的对象上使用new(并且在覆盖的情况下operator new,或 C++ 运行时的多个副本,在当前范围内找到的特定new匹配项)delete

于 2011-09-16T19:21:08.453 回答
0

释放时的崩溃可能很痛苦:它不应该发生,当它发生时,代码太复杂而无法轻易找到解决方案。

注意:使用InterlockedDecrement让我假设您在 Windows 上工作。

记录一切

我自己的解决方案是大量记录构造/破坏,因为在调试时崩溃很可能永远不会发生:

  1. 记录构造,包括this指针值和其他相关数据
  2. 记录销毁,包括this指针值和其他相关数据

这样,您将能够查看 是否this被释放了两次,甚至根本没有分配。

...一切,包括堆栈

我的问题发生在托管 C++/.NET 代码中,这意味着我可以轻松访问堆栈,这是一件幸事。您似乎在使用纯 C++,因此检索堆栈可能是一件苦差事,但它仍然非常有用。

您应该尝试从 Internet 加载代码以打印出每个日志的当前堆栈。我记得为此玩过http://www.codeproject.com/KB/threads/StackWalker.aspx

请注意,您需要在调试版本中,或者在可执行文件中包含 PDB 文件,以确保堆栈将被完全打印。

...一切,包括多次崩溃

我相信您在 Windows 上:您可以尝试捕获 SEH 异常。这样,如果发生多次崩溃,您将看到所有崩溃,而不是只看到第一次,并且每次您都可以在日志中标记“OK”或“CRASHED”。我什至使用地图来记住分配/解除分配的地址,从而组织日志以将它们一起显示(而不是按顺序显示)。

我在家,所以我无法为您提供确切的代码,但在这里,Google 是您的朋友,但要记住的是,您不能到处都有__try/处理程序(C++ 展开和 C++ 异常处理程序是__except与 SEH 不兼容),因此您必须编写一个中间函数来捕获 SEH 异常。

你的崩溃线程是相关的吗?

最后但并非最不重要的一点是,“我只发生了 5% 的时间”症状可能是由不同的代码路径执行引起的,或者是由于多个线程一起处理相同的数据。

InterlockedDecrement部分让我很困扰:你的对象是否存在于多个线程中?m_nRefCount 是否正确对齐volatile LONG

正确对齐和LONG部分很重要,在这里。

如果您的变量不是 a LONG(例如,它可能是 a ,这在 64 位 Windows 上size_t不是 a ),那么该函数很可能会以错误的方式工作。LONG

对于未在 32 字节边界上对齐的变量也可以这样说。#pragma pack()您的代码中有说明吗?您的项目文件是否更改了默认对齐方式(我假设您正在使用 Visual Studio)?

对于该volatile部分,InterlockedDecrement似乎会生成读/写内存屏障,因此该volatile部分不应该是强制性的(请参阅http://msdn.microsoft.com/en-us/library/f20w0x5e.aspx)。

于 2011-09-18T10:05:50.433 回答