【问题标题】:Other Possible Reasons for std::bad_alloc being thrown抛出 std::bad_alloc 的其他可能原因
【发布时间】:2011-12-25 15:58:11
【问题描述】:

我正在开发一个相当大的 SIP 电话应用程序,有时当我们在繁重的呼叫负载下使用集成的 Web UI(使用 tntnet 编写)时,由于抛出 std::bad_alloc,程序将退出。有数百个线程在使用(每个活动调用 3 个),因此导致异常的代码位置非常随机,但总是在使用 GUI 之后。

现在,我了解到 std::bad_alloc 在内存不足时会被抛出,但在这种情况下并非如此。我还认为当堆损坏时可以抛出它,我仍在寻找它在代码库中的任何位置。

但我的问题是,除了内存不足或堆损坏之外,还有其他原因会抛出 std::bad_alloc 吗?我在 Linux 上使用 GNU g++。

【问题讨论】:

  • 我不知道或见过。
  • bad_alloc 仅在分配内存失败时被抛出,但正如您所注意到的,如果您的程序做了任何未定义的事情,它可能会做任何事情,包括在未定义操作之后的任何时间抛出 bad_alloc
  • @Chris Dodd:还是在未定义行为之前,我相信!

标签: c++ linux exception g++ heap-memory


【解决方案1】:

在 linux 上,当前的地址空间限制可用于人为地限制进程可以使用的内存量。您可以使用setrlimit(RLIMIT_AS, ...) 手动设置它。这也可以使用ulimit -vbashrc 中的整个shell 设置。这也可以在/etc/security/limits.conf 中为整个系统设置。这个地方甚至可能有一个 /proc/sys 条目,我不确定。

如果达到地址空间限制,您的进程将在尝试分配更多内存时抛出 std::bad_alloc。在 64 位系统上,这可能是一个很好的“安全措施”,以确保错误的应用程序或库不会耗尽可用内存并使系统完全交换或停止工作。确保程序没有在某个地方设置它,并确保环境的其余部分也没有设置它。你可以在程序中间的某个地方插入一些代码来调用getrlimit(RLIMIT_AS, ...),以确保它没有偷偷溜到某个地方。

一个可能更常见的原因(当然,除了实际耗尽内存之外)是无符号整数环绕情况,其中 uin32_t 或 uint64_t 用于分配内存但为 0 并从中减去 1,导致一个非常大的请求分配(在 64 位中将是数千 PB)。

无论如何,最好的方法是使用 GDB。如果您的应用程序根本不使用异常(因此根本没有“catch”语句),那么您可以启用核心文件(ulimit -c unlimited)。下次程序崩溃时,操作系统会生成一个核心文件,并将其加载到 GDB 中会立即给您一个回溯,显示程序崩溃的位置。

如果你有几个(但不是很多)地方使用了 try 并且它捕获了这些错误的分配,除了在调试这个问题时将它们注释掉,你可以在 GDB 中运行应用程序并使用 catch throw每次抛出异常时让 GDB 中断的命令。要使其中任何一个起作用,切勿使用 -fomit-frame-pointer 进行编译,而始终使用 -ggdb 进行编译(即使使用 -O3)。

【讨论】:

    【解决方案2】:

    很可能,您确实内存不足。这将是一个极其罕见的堆损坏错误,始终导致 only bad_alloc 被抛出。这就像以外科手术般的精确度涂鸦。

    可能只是代码中存在分配大量内存的错误。但是您会期望在该代码中至少在很大一部分时间会抛出异常。异常来自许多不同的地方这一事实与此相反。

    严重的碎片可能会导致问题,尤其是对于 malloc 实现不佳的平台。这种情况很少见,但确实会发生。

    我会立即做一件事——捕获异常并调用一个函数来保存/proc/self/maps 的副本。这将使您对进程的峰值内存使用情况有一个很好的了解。您可以判断它是否接近任何平台、策略或硬件限制。

    【讨论】:

      猜你喜欢
      • 2012-08-08
      • 1970-01-01
      • 2011-05-20
      • 2012-08-24
      • 2016-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多