内存分配崩溃

Posted

技术标签:

【中文标题】内存分配崩溃【英文标题】:Memory Allocation Crash 【发布时间】:2010-11-14 08:40:39 【问题描述】:

我偶然发现了一个我无法理解的奇怪问题。我不是 C/C++ 方面的专家,所以请耐心等待。我有一个 NPC 类,它派生自一个 Player 类,它派生自 Sprite 类。 sprite 类包含一个 setupAnimation 函数,它分配一个浮点数组,其中包含纹理上的坐标,数组的每个元素都指一帧动画。这一切都很好,工作正常。

但是,当我向 NPC 类添加一个指针数组时,会出现问题。这些指针属于 Item 类类型。当我添加这个数组时,如果数组很小(10 是我测试的大小),它工作正常,但是如果大小有点大(100 是我测试的大小),在为前面提到的纹理坐标分配浮点数组时会崩溃测试)。

下面是一些代码片段,展示了我上面提到的材料:

Item 类指针数组:

    engItem* itsLoot[100]; // With 100 here, the crash occurs as shown below

纹理坐标及其对应的分配:

    GLfloat* itsTextureXData;
    GLfloat* itsTextureYData;

    ...

    animationFile >> frameCount; // Tested, the value is correct

    engDeallocate(getTextureXData(), true); // Works fine
    itsTextureXData = new GLfloat[frameCount]; // This is where the crash occurs

    engDeallocate(getTextureYData(), true);
    itsTextureYData = new GLfloat[frameCount];

这段代码是从 Sprite 类派生的每个类的基础。我无法理解的是为什么额外的 90 个指针会在浮点分配期间导致问题。只需一点软件信息就可以了

操作系统:Windows Vista 32 位,编译器:Visual C++ 9.0,程序运行时内存:~17,600k,系统内存:~2GB

考虑到这一点,我看不到它正在耗尽内存,并且我无法了解指针数组如何导致分配失败。如前所述,分配在从 Sprite 派生的所有其他类(以及 Sprite 本身)中工作正常,但是一旦将此指针数组添加到 NPC 类,NPC 将不再分配此纹理数据浮点数组而不会崩溃。

【问题讨论】:

什么是崩溃?也就是说,调用堆栈和异常代码或断言是什么? 【参考方案1】:

在你的程序的其他地方,你可能有某种内存错误(写到数组的末尾,写到释放的内存,等等)。发生这种情况时,您可能会覆盖内存分配系统使用的结构,导致它在下一次分配时崩溃。使用Valgrind 之类的工具来运行您的程序以找出错误所在可能会有所帮助。 编辑: 我刚刚意识到您使用的是 Windows,而 Valgrind 只能在 Linux 上运行。如果您的代码足够可移植,那么尝试 Linux 和 Valgrind 会相对容易。如果您不能这样做,请参阅 SO 上的 Is there a good Valgrind substitute for windows?。 (不幸的是,看起来它们中的大多数都是商业的,而不是像 Valgrind 那样免费和开源。)

避免这种情况的最佳方法是使用 C++ 集合,例如 std::vectorstd::list,而不是数组。如果您使用这些集合,请确保将复制保持在最低限度(例如,使用const 引用作为参数而不是原始对象的副本,如果您不修改它等),否则您将获得非常糟糕的性能(看起来你在玩游戏,所以这很重要)。

【讨论】:

感谢您的快速回复。我已经尽可能多地引用了。我会更频繁地使用矢量,但我总是不喜欢那些做我自己能做的事情的库,因为它们是以我不喜欢的方式设置的。这是我认识的一个糟糕程序员的基础,我很可能会摆脱它。无论如何,再次感谢,非常感谢(以及感谢上面的尼尔)。 我现在就开始改变。重新发明***是可怕的。他们的设置不是你喜欢的怎么办?【参考方案2】:

您描述的症状是内存分配系统损坏的典型症状。错误发生在您所说的地方可能并不重要 - 真正的错误几乎肯定在其他地方。

有很多方法可以减少这种情况发生的可能性,但主要的一种 是用 C++ 编写代码,而不是用一点 C++ 语法编写的 C。使用像 std::vector 这样的集合来执行自己的内存管理,而不是尝试自己做。

【讨论】:

【参考方案3】:

如前所述,这很像内存损坏。

要缩小真正错误所在的位置,请在调试模式下运行并尝试增加 CRT 检查堆是否损坏的频率。

以下取自 MSDN 的代码展示了如何让 CRT 每 16 次而不是每 1024 次检查一次堆操作:

#include <crtdbg.h>
int main( )

int tmp;

// Get the current bits
tmp = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);

// Clear the upper 16 bits and OR in the desired freqency
tmp = (tmp & 0x0000FFFF) | _CRTDBG_CHECK_EVERY_16_DF;

// Set the new bits
_CrtSetDbgFlag(tmp);

欲了解更多信息,请参阅_CrtSetDbgFlag in MSDN

【讨论】:

以上是关于内存分配崩溃的主要内容,如果未能解决你的问题,请参考以下文章

cuda - 内存分配崩溃

C ++释放共享库中动态分配的内存导致崩溃

当内存不足时,c ++分配器使应用程序崩溃[重复]

内存分配问题,设备 iOS SDK 4.1 崩溃(线程 0 崩溃)

Android 4.0.3 模拟器崩溃:分配内存失败:8

RabbitMQ/Erlang 崩溃:无法重新分配 313760 字节的内存(“代码”类型)