新对象导致堆上的损坏

时间:2011-06-24 19:43:14

标签: c++ heap gflags

我几天都在努力解决堆腐败问题。我第一次被vs 2005调试器警告我可能已经损坏了堆,删除了我以前新建的对象。对这个问题进行研究后,我得到了gflags和页面堆设置。在为我的特定图像启用此设置后,它应该指向我实际导致损坏的行。

Gflags将相关对象的构造函数识别为罪魁祸首。该对象派生如下:

class POPUPS_EXPORT MLUNumber :  public MLUBase
  {
...
  }
class POPUPS_EXPORT MLUBase : public BusinessLogicUnit
  {
...
  }

我可以在单独的线程中实例化MLUNumber,并且不会发生堆损坏。

我可以实例化一个不同的类,它也继承自MLUBase,不会导致堆损坏。

由于在构造函数的左大括号上发生损坏而导致访问冲突,这似乎是由于对象的隐式初始化(​​?)。

基类构造函数(MLUBase)成功完成。

从使用vs 2005中的内存窗口挖掘,似乎没有为实际对象分配足够的空间。我的猜测是,仅为基类分配了足够的内容。

导致错误的行:

BusinessLogicUnit* biz = new MLUNumber();

我希望有任何可能导致此问题的原因或其他问题排查步骤。

5 个答案:

答案 0 :(得分:6)

不幸的是,根据所提供的信息,无法明确诊断出问题。

您可能想要检查的一些事项:

  • 确保BusinessLogicUnit具有虚拟析构函数。当delete对象通过基指针时,基类中必须存在虚拟析构函数才能正确销毁子类。
  • 确保使用相同的预处理程序标志和编译器选项构建所有源文件。标志的差异(可能在调试/释放标志之间?)可能导致结构大小发生变化,从而导致不同源文件中报告的大小不一致。
  • 即使使用gflags设置,某些类型的堆损坏也可能无法检测到。审核您的其他堆使用以尝试查找问题的来源。理想情况下,您应该将一个最小的测试用例组合在一起,这个测试用例会可靠地崩溃,但只需要最少量的活动,因此您可以缩小原因。
  • 尝试一个干净的解决方案并重建;我偶尔会看到时间戳搞砸了,旧的目标文件可以使用过时的结构定义。值得检查至少:)

答案 1 :(得分:2)

BusinessLogicUnit* biz = new MLUNumber();

如何删除内存?使用基类指针?你有BusinessLogicUnit虚拟的析构函数吗?它必须是virtual

class BusinessLogicUnit
{
  public:
      //..
      virtual ~BusinessLogicUnit(); //it must be virtual!
};

否则,通过基类指针删除派生类对象会根据C ++标准调用未定义的行为。

答案 2 :(得分:0)

BusinessLogicUnit 不是 MLUNumber。你为什么这样分配?代替 BusinessLogicUnit * biz = new BusinessLogicUnit();

答案 3 :(得分:0)

或者你可能会这样做?

struct A
{
    SomeType & m_param;

    A(SomeType & param) : m_param(param)
    {
        ...use m_param here...
    }
};

A a(SomeType()); // passing a temporary by reference

然后这是未定义的行为,因为引用的临时在m_param(param)发生后立即死亡。

答案 4 :(得分:0)

我同意bdonlan的说法,还没有足够的信息来弄清楚什么是错的。这里有很多好的建议,但只是猜测应用程序崩溃的可能原因并不是导致问题的明智方法。

通过启用检测(pageheap)来帮助您缩小问题范围,您已经做了正确的事情。我会通过找出导致访问冲突的确切内存地址(以及地址来自哪里)继续沿着这条路走。