45

我的程序中有一个相当严重的错误——偶尔调用 new() 会抛出一个 bad_alloc。

从我可以在 bad_alloc 上找到的文档中,它似乎是由于以下原因而抛出的:

  1. 当计算机内存不足时(这绝对没有发生,我有 4GB 的 RAM,当使用少于 5MB 的内存(在任务管理器中检查)时程序抛出 bad_alloc,而后台没有任何严重的运行)。

  2. 如果内存变得太碎片化而无法分配新块(这同样不太可能 - 我曾经分配的最大块大小约为 1KB,并且在崩溃发生之前不会超过 100 次)。

根据这些描述,我真的没有任何地方可以抛出 bad_alloc。

但是,我正在运行的应用程序运行多个线程,这可能是导致问题的原因。通过在单个线程上测试所有对象,一切似乎都很顺利。我能想到的唯一另一件事可能是同时在多个地方调用 new() 引起的某种竞争条件,但我尝试添加互斥锁以防止这种行为没有效果。

因为程序有几百行,而且我不知道问题出在哪里,所以我不确定要发布什么(如果有的话)代码片段。相反,我想知道是否有任何工具可以帮助我测试这种事情,或者是否有任何通用策略可以帮助我解决这个问题。

我正在使用 Microsoft Visual Studio 2008 和 Poco 进行线程处理。

4

6 回答 6

26

当你有一个错误覆盖堆用来管理它用来分配的内存池的指针时,也可以抛出 bad_alloc。

最常见的原因是您正在写入已分配内存块的末尾(或在开始之前,但这不太常见)。几乎同样常见的是在内存块被释放后写入内存块。这称为堆损坏。

另外,我应该注意,Windows 中的 32 位进程最多有 2GB 的地址空间(3GB 用于大地址感知程序)。这与您安装了多少 RAM、内存是虚拟的、分配不会失败直到地址空间用完无关,即使您只有 1GB 的 RAM。

这是关于 C++ 中内存损坏的一个很好的讨论http://www.eventhelix.com/RealtimeMantra/Basics/debugging_software_crashes_2.htm

于 2010-03-20T04:45:23.097 回答
23

另一个可能的问题是,虽然您提到该程序使用的空间少于 5MB,但您没有提及它试图分配多少空间。您可能有一些竞争条件破坏了您用于确定分配大小的值,并且它可能正在尝试分配 37TB 或类似的废话。

我想这不太可能,但值得检查。

于 2010-03-20T04:56:10.560 回答
3

几点说明:

Windows 中的每个进程获得 4GB 虚拟内存,其中 2GB 用于用户空间,其余用于内核空间。4GB 的 RAM 不会用于虚拟内存,而是用于物理内存。

在 2GB 内存中,所有 EXE、DLL 都被加载,几乎没有 1.6 - 1.7GB 可用于内存分配。在此内存中,如果没有连续的内存进行分配,则内存分配失败。

于 2010-03-20T04:41:27.713 回答
1

bad_alloc 也可以被其他代码抛出。

我已经看到它被设计用于 STL 容器的有限内存池使用。当达到大小限制时,它会抛出 bad_alloc 并且软件只需要处理它。

于 2010-04-03T02:41:01.680 回答
1

我之前实际上遇到过这个问题,并通过清理和重建项目来解决。当你有奇怪的行为时总是值得一试(除非它是一个需要数小时编译的巨大项目)。

于 2013-08-29T15:21:25.287 回答
1

对此进行调试的一种策略是在调试器中设置一个捕获点。在 gdb 中,只要程序抛出异常,就会说“catch throw”来询问您停止的调试器。如果程序在其正常业务过程中抛出并捕获大量异常,您可以对其进行改进以仅捕获 std::bad_alloc。调试器将在生成 std​​::bad_alloc 的任何分配函数内停止,允许您四处寻找。在这种情况下,您会很快了解到请求的字节数不是您所期望的。

于 2019-11-08T21:19:11.170 回答