试图在我的小型计算机上构建一个矩阵,数组大小变大,它耗尽了内存容量然后我得到了一个segv,我想知道C ++中是否有办法检测segv而不跳出来然后继续?
unsigned m = 10000;
unsigned n = 10000;
double mat[m][n];
for (unsigned i = 0; i < m; ++i)
{
for (unsigned j = 0; j < n; ++j)
{
double tmpNum1 = rand()%precisionA;
double tmpNum2 = tmpNum1/precisionA+rand()%precisionB;
mat[i][j] = tmpNum2;
}
}
if (segv) // How to do this???
{
cout<< "Buy a new computer please!" << endl;
}
else
{
cout<< "Good, get a coffee for yourself!" << endl;
}
Edit1:有时错误是segv,有时是"terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc Aborted (core dumped)"
Edit2:在这里使用Ubuntu。
答案 0 :(得分:7)
10000x10000 double
的数组大约为800MB,您将该数组完全放在堆栈上。所以,当然它将是SEGV:我所知道的系统没有分配几乎GB的堆栈内存。
使用new
在堆上分配它,它应该可以正常工作。
至于如何捕获SEGV,这是特定于平台的。在某种意义上,SEGV是由程序引起的对未定义行为的许多可能响应之一。捕获SEGV绝不会捕获程序因这种未定义的行为而失败的所有可能方式。
在Windows上,您可以使用structured exception handler来捕获无效访问引发的访问冲突异常。
在POSIX系统上,您可以使用signal handler来捕获SIGSEGV。
但是,请记住,由于堆栈溢出(在这种情况下会发生这种情况),您的程序还有其他方法可能会死亡。您的堆栈可能会增长到目前为止与堆相交,导致堆损坏;您的操作系统可能无法捕获无效访问,并在以后发生无关错误时崩溃; libc
可能会在检测到堆栈碎片或任何其他错误后调用abort()。因此,捕获SEGV的最佳方法是首先修复它。
答案 1 :(得分:2)
您可以使用signal()函数拦截SIGSEGV等信号:
http://www.cplusplus.com/reference/csignal/signal/
请注意,在您的情况下,您将矩阵分配到程序的堆栈中,这相当小(在Linux上大约为8MB左右)。
您可能希望使用动态分配(new
运算符)来分配矩阵。这样做会将矩阵存储到程序堆中,您可以在其中存储更多数据。
答案 2 :(得分:1)
要捕获由operator new
(C ++)引起的堆分配失败,您需要在try/catch块上包含对它的调用,然后捕获std::bad_alloc
异常。
如果您使用malloc()/calloc()
和朋友分配内存,只需检查返回值即可。错误或分配失败时为NULL。
对于由递归,大堆栈分配的数组或alloca()
引起的堆栈溢出,有两种方法可以处理我所知道的异常。在Windows上,您可以使用结构化异常处理(SEH)。另一种方法是使用C Signals API。
答案 3 :(得分:-1)
您的mat
数组无效C ++
使用new / delete,或std :: array,std :: vector ...
然后你可以捕获预期std :: bad_alloc
(我理解你的意思,但为什么用“segv”这个词?)