程序以std :: bad_alloc终止

时间:2013-08-18 21:08:26

标签: c++ memory-management

我正在运行一个C ++程序,它在任意点死于std::bad_alloc,这取决于指定的输入。以下是关于该计划的一些观察/观点:

  • 对于较短的运行(运行时间取决于输入),程序正常完成。这个问题只适用于较大的运行。
  • 程序没有任何可检测到的内存泄漏。对于较小的运行,使用Valgrind / Memcheck检查了这一点。此外,我的整个代码没有任何指针(所有动态分配都由库完成,例如,在std::vectorstd::string;这些库类中的分配失败了),因此内存泄漏非常不可能。
  • 在循环中分配几个对象,然后移动到容器。其中一些对象在程序即将结束之前一直存在。
  • 我怀疑堆碎片可能是一个问题(参见C++ program dies with std::bad_alloc, BUT valgrind reports no memory leaks)但是我使用的是64位系统,带有64位编译器(特别是带有g ++的Linux),Heap fragmentation in 64 bit land让我相信堆碎片在64位系统上不是问题。

还有什么我应该尝试的吗?任何可以帮助的特定工具?还有其他建议吗?

更新:最后证明虚拟内存早先被ulimit -v限制。我后来忘了这件事,因此内存耗尽。将其重新设置为unlimited可解决问题。

2 个答案:

答案 0 :(得分:5)

std::bad_alloc表示您请求的内存比可用内存多。

您可以遇到程序没有泄漏但仍然真正耗尽内存的情况:

vector<long> v;
long n = 0;
for(;;)
{
   v.push_back(n++);
}

最终将耗尽你所拥有的任何机器中的所有可用内存 - 但它不会泄漏 - 所有内存都在向量中占用。显然,任何容器都可以做同样的事情,vectorlistmap,并不重要。

Valgrind只找到你“放弃”分配的实例,而不是用当前可达内存填充系统的地方。

正在发生的是一种较慢的形式 - 你在一些容器中存储的越来越多。它可能是您正在缓存的内容,或者您​​认为已删除它时未删除的内容。

观察应用程序上的内存量实际上是在一些监控程序中使用(Linux / Unix中的“top”,Windows中的“任务管理器”)并查看它是否实际增长。如果是这种情况,那么你需要弄清楚正在发展的是什么 - 对于一个大型项目来说,这可能很棘手(有些事情可能会成长,有些则不会......)

当然,您可能会突然得到一些不好的计算,例如:在T* p = new T[elements];中要求负数的元素会导致错误的分配,因为元素被转换为无符号,而负无符号数是巨大的。

如果您可以在调试器中捕获bad_alloc,那么通常很容易发现这种情况,因为new请求的大量数据将非常明显。

在调试器中捕获异常应该是一般的帮助,虽然当然可能你只是在出错时为一个小字符串分配内存,如果你确实有泄漏的东西,这就是这个并不罕见当它出错时分配。

如果您正在使用Unix的风格,您还可以使用ulimit -m size(以千字节为单位)或者加速错误查找,将应用程序允许使用的内存量设置为较小的大小。 ulimit -v size

答案 1 :(得分:1)

std::bad_alloc可能也意味着您正在请求负数的数据,即使计算机中有足够的内存也是如此。

这种情况在我的64位linux机器上很容易发生,当我使用常规的有符号整数(仍然是32位)而不是长整数(64位)来指定数组计数时,我将两个数字相乘太大而无法获得最终数量。乘法结果在2.147Gig处安静地溢出,因此可能变为负数。

例如,您要在21维空间中分配1亿个点。没问题。计数是2,100,000,000。现在将尺寸尺寸增加到22,它会从悬崖上掉下来。这很容易通过printf验证:

int N = 100000000;
int D = 22;
int count = N * D;
printf("count = %'d\n", count);

给予

count = -2,094,967,296

std::bad_alloc插入,因为请求的内存计数为负。

Ed .:我在评论中指出这似乎是无法再现的结果,因为现在new [count]在重启机器后给出了std::bad_array_new_length。也就是说,代码仍然不正确并且会中断,但是给出的错误消息与以前不同。无论哪种情况都不要这样做。