如何在C+;中使用堆栈但避免堆栈溢出+; 我现在正从java中移回到C++。有一些C++领域,通过在栈上做更多的计算,可以获得更高的性能。一些递归算法在堆栈上比堆上更有效。

如何在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

很明显,堆栈是一种资源,如果我要使用它,我应该确保不会消耗太多(以至于程序崩溃)

我正在运行Xcode,并编写了以下简单程序:

#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,


在C++中,这和Java有同样的问题。您已经远远超过了对堆栈的承诺

一些递归算法在堆栈上比在堆上更有效

事实上,它们通常是分而治之的类型。 递归的用途是在每次调用时将计算简化为更易于管理的计算<代码>限制-1不是这样的候选项


如果您的问题只是关于信号,很遗憾,我无法为您的系统提供任何建议。

您的信号处理程序无法解决堆栈溢出问题。设置
中断
标志没有帮助。当信号处理程序返回时,尝试写入堆栈末尾以外地址的指令将恢复,并且它仍将尝试写入堆栈末尾以外的地址。您的代码不会返回到检查您的
中断
标志的部分

如果非常小心并编写大量特定于体系结构的代码,您的信号处理程序可能会更改遇到信号的线程的上下文,这样,当信号恢复时,它将位于代码中的不同点

您还可以使用
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(<代码> >和 LojMP()/<代码>似乎是改进粒度的方法。何时C++会抛出StaskOyExpLoad异常?与使用
setjmp()
long jump()
相比,哪种方法更为优雅?关于特定于体系结构的代码,我们可以简单地检查堆栈指针,以及堆栈的分配位置,以确定“剩下多少堆栈?”这样就可以避免在到达边界后进行异常处理。