如何在C+;中使用堆栈但避免堆栈溢出+; 我现在正从java中移回到C++。有一些C++领域,通过在栈上做更多的计算,可以获得更高的性能。一些递归算法在堆栈上比堆上更有效。
很明显,堆栈是一种资源,如果我要使用它,我应该确保不会消耗太多(以至于程序崩溃) 我正在运行Xcode,并编写了以下简单程序:如何在C+;中使用堆栈但避免堆栈溢出+; 我现在正从java中移回到C++。有一些C++领域,通过在栈上做更多的计算,可以获得更高的性能。一些递归算法在堆栈上比堆上更有效。,c++,macos,stack-overflow,exc-bad-access,C++,Macos,Stack Overflow,Exc Bad Access,很明显,堆栈是一种资源,如果我要使用它,我应该确保不会消耗太多(以至于程序崩溃) 我正在运行Xcode,并编写了以下简单程序: #include <csignal> static bool interrupted = false; long stack_test(long limit){ if((limit>0)&&(interrupted==false)) return stack_test(limit-1)+1; // program
#include <csignal>
static bool interrupted = false;
long stack_test(long limit){
if((limit>0)&&(interrupted==false))
return stack_test(limit-1)+1; // program crashes here with EXC_BAD_ACCESS...
else
return 0;
}
void signal_handler(int sig){
interrupted = true;
}
int main(char* args[]){
signal(SIGSEGV,&signal_handler);
stack_test(1000000);
signal(SIGSEGV,SIG_DFL);
}
#包括
静态布尔中断=假;
长堆试验(长限){
如果((限制>0)和&(中断==假))
return stack_test(limit-1)+1;//程序在这里崩溃,EXC_访问错误。。。
其他的
返回0;
}
无效信号处理器(int sig){
中断=真;
}
int main(字符*参数[]){
信号(SIGSEGV和信号处理器);
堆叠测试(1000000);
信号(SIGSEGV、SIG_DFL);
}
文档说明,在BSD上运行时,可以使用getrlimit()
检查堆栈限制,当达到堆栈限制时,会发出SIGSEGV
事件。我尝试为这个事件安装上面的事件处理程序,但是,我的程序在下一次迭代时停止了EXT\u BAD\u访问(code=2,
…)
如果您的问题只是关于信号,很遗憾,我无法为您的系统提供任何建议。您的信号处理程序无法解决堆栈溢出问题。设置
中断
标志没有帮助。当信号处理程序返回时,尝试写入堆栈末尾以外地址的指令将恢复,并且它仍将尝试写入堆栈末尾以外的地址。您的代码不会返回到检查您的中断
标志的部分
如果非常小心并编写大量特定于体系结构的代码,您的信号处理程序可能会更改遇到信号的线程的上下文,这样,当信号恢复时,它将位于代码中的不同点
您还可以使用setjmp()
和longjmp()
以更粗的粒度完成这项工作
另一种方法是使用
pthread\u attr\u setstackaddr()
和pthread\u attr\u setstacksize()
在pthread\u create()
之前,设置一个线程以使用代码分配的堆栈。您将在该辅助线程而不是主线程中运行代码。您可以使用mprotect()
将分配的堆栈的最后一页或两页设置为不可写。然后,您的信号处理程序可以设置中断
标志,并将这些页面设置为可写。这将为您提供足够的净空,使恢复的代码可以在不重新发出信号的情况下执行,并获得足够的距离来检查标志,然后优雅地返回。请注意,这是一种一次性的最后手段,除非您能找到一个很好的方法将这些保护页再次设置为不可写。也许1000000还不够?你试过增加吗?无论如何,我会在你的例子中使用迭代而不是递归。堆栈溢出后,无法继续迭代递归。2.如果您使用gcc,您可以通过将参数传递给链接器来更改堆栈大小。请看这里:(接受的答案)。您是在尝试完成某件事情,还是只是好奇?捕捉那个信号没有什么意义,因为当它发生时,你无能为力。我正试图优雅地处理溢出。。。通过中断递归(interrupted==false)
将不再为真,堆栈将被取消堆栈…我相信您不能这样做,因为信号是异步的。在您的上述代码已经尝试访问禁止的内存后,它们将被发送/捕获/处理。同意应减少计算,但我在这里故意尝试处理或预防溢出情况(否则我如何设置边界?),我认为我的调试器在这里出了问题。EXC_BAD_访问是一个Mach微内核异常,(de)bugger(!)正在连接到它,它在BSD层生成信号之前得到处理。虽然在没有调试器的情况下调试信号处理程序看起来并不有趣…同意<代码> > SETJMP(<代码> >和setjmp()
和long jump()
相比,哪种方法更为优雅?关于特定于体系结构的代码,我们可以简单地检查堆栈指针,以及堆栈的分配位置,以确定“剩下多少堆栈?”这样就可以避免在到达边界后进行异常处理。