运行此代码时:
#include <iostream>
#include <vector>
#include <deque>
template< typename C >
void fillToMax( C & collection, typename C::value_type value )
{
try
{
while( true )
collection.push_back( value );
}
catch( std::bad_alloc const& )
{
std::cout << "bad alloc with size " << collection.size() << std::endl;
}
return;
}
void fillVector()
{
std::vector<long> vecL;
fillToMax( vecL, 123 );
}
void fillDeque()
{
std::deque<long> deqL;
fillToMax( deqL, 123 );
}
int main()
{
fillVector();
fillDeque();
}
我收到了预期的bad_alloc
错误,因此很容易尝试/捕获。
问题是当我用vector
替换deque
时,在这种情况下我的机器崩溃了...黑屏,重新启动以及再次声称:你遇到了意想不到的问题!
我想使用deque
代替vector
来存储更多的项目而不会出现连续的空间问题。这将使我能够存储更多数据,但我无法承受我的应用程序崩溃,并想知道如何将其转换为bad_alloc。
这可能吗?
我的测试在win8.1上使用MinGW-W64 - gcc版本4.8.2(x86_64-posix-seh-rev4)
答案 0 :(得分:4)
你不会说你正在使用什么系统,所以很难说,但是 一些系统&#34; overcommit&#34;,这基本上使符合 实现C ++(甚至C)是不可能的;系统会 说没有内存可用,并且崩溃 当你尝试使用它。 Linux是最广泛记录的 罪魁祸首在这里,但您可以重新配置它以正常工作。
你得到bad_alloc
向量的原因是因为向量
分配更大的块。即使有过度使用,也是如此
如果块太大,系统将拒绝分配内存。
此外,许多malloc将使用不同的分配策略
非常大的块; IIRC,Linux中的malloc切换到使用
超出一定规模的mmap
,系统可能会拒绝mmap
即使sbrk
成功了。
答案 1 :(得分:1)
为什么矢量可能会崩溃而不是deque的快速答案是因为vector使用连续的缓冲区你将bad_alloc“更快”。而且还要求一大块。
为什么呢?因为您不太可能分配连续的缓冲区而不是较小的缓冲区。
vector
将分配一定数量,然后为更大的缓冲区尝试一个大的“realloc”。有可能扩展当前的内存空间但可能没有,并且可能需要找到一大堆新的内存。
让我们说它看起来要扩大1.5倍。因此,您当前在使用的向量中有40%的可用内存,它需要找到60%的可用内存,但无法在当前位置执行此操作。好吧,它会带你到极限,所以它失败了bad_alloc
,但实际上你只使用了40%的内存。
所以实际上有可用内存,那些使用“乐观”内存分配的操作系统不会意外地为你分配过多。你已经要求了很多而且它无法给你。 (他们并不总是非常乐观)。
另一方面, deque
一次要求一个块。你真的会耗尽你的记忆力,因此最好用于大型系列,但是它有一个缺点,当你内存不足时你确实用完了。而你可爱的乐观内存分配器无法处理它,你的进程就会死掉。 (它会杀死一些东西以增加记忆力。可悲的是它是你的。)
现在为您解决如何避免它发生的问题?您的答案可能是自定义分配器,即deque的第二个参数,它可以检查可用的实际系统内存,如果达到某个阈值则拒绝分配。
当然它取决于系统,但您可以为不同的机器使用不同的版本。
当然,您也可以设置自己的任意“限制”。
假设您的系统是Linux,您可以通过
关闭过度使用'echo 2 > /proc/sys/vm/overcommit_memory'
您需要root(admin)权限才能执行此操作。 (或者让那些拥有它的人以这种方式配置它。)
否则,Linux手册中提供了检查内存使用情况的其他方法,通常在/proc
中提及。
如果您的系统不是Linux而是另一个过度提交的系统,那么您必须通过编写自己的内存管理器来查找如何绕过它。否则,请采用任意可配置最大大小的简单选项。
请记住,对于deque
,只有在需要分配新的“块”而不是每个push_back
时才会调用分配器。
答案 2 :(得分:0)
Xarylem,只是试图回答&#34;我该如何防止这种情况发生?在这......
你知道抛出bad_alloc - std :: vector的东西。 你知道崩溃的东西...... std :: deque。
因此,一种方法是创建一个大小为X的新向量,如果成功,则清除向量并将X更多地推回到双端队列中。如果它没有,你知道你正陷入泥潭。类似的东西:
std::vector<int> testVector;
testeVector.reserve(1);
std::deque<int> actualDequeToFill;
for(size_t i = 0; ; ++i)
{
//test first
bool haveSpace = false;
try { testVector.reserve(2); } catch(...) { haveSpace = false; }
vector.reserve(1);
if (!haveSpace) throw new std::bad_alloc("Vector shows no space left");
deque.push_back(something);
}
这并非接近于万无一失......所以请将其用作解决方法的可能想法,而不是作为实现。
现在暂且不说了,我最好的猜测是......你的编译器不合规......正如我在评论中提到的那样,C ++ 需要 deque :: push_back来扔bad_alloc。如果可以,请远离该编译器(这是正确的基本内容)