[英]How do I use the stack but avoid a stack overflow in C++
我現在正從Java轉回C ++。 C ++的某些領域可以通過在堆棧上進行更多計算來實現更高的性能。並且一些遞歸算法在堆棧上比在堆上更有效地運行。
顯然堆棧是一種資源,如果我要使用它,我應該確保我不會消耗太多(為了使我的程序崩潰)。
我正在運行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);
}
文檔說明在BSD上運行,可以使用getrlimit()
檢查堆棧限制,並且當達到堆棧限制時,將發出SIGSEGV
事件。 我嘗試為此事件安裝上述事件處理程序,但是,我的程序在下一次迭代時使用EXT_BAD_ACCESS (code=2,
... )
停止。
我在這里采取了錯誤的方法,還是有更好的方法?
這在Java中與在c ++中具有相同的問題。 你是過度承諾的堆棧。
並且一些遞歸算法在堆棧上比在堆上更有效地運行。
實際上,它們通常屬於分而治之的類型。 遞歸的有用性是將計算減少到每次調用更易於管理的計算。 limit - 1
不是這樣的候選人。
如果您的問題僅與信號有關,我很遺憾無法就您的系統提供任何建議。
您的信號處理程序無法解決堆棧溢出問題。 設置interrupted
標志沒有幫助。 當您的信號處理程序返回時,嘗試寫入堆棧末尾之外的地址的指令將恢復,並且它仍將嘗試寫入超出堆棧末尾的位置。 您的代碼將無法返回檢查interrupted
標志的部分。
非常謹慎和許多特定於體系結構的代碼,您的信號處理程序可能會改變遇到信號的線程的上下文,這樣當它恢復時,它將處於代碼中的不同點。
您還可以使用setjmp()
和longjmp()
以更粗略的粒度完成此操作。
一種不同的方法是建立一個線程來使用你的代碼分配的堆棧,使用pthread_attr_setstackaddr()
和pthread_attr_setstacksize()
之前pthread_create()
您將在該輔助線程中運行您的代碼而不是主要代碼。 您可以使用mprotect()
將分配的最后一頁或兩個堆棧設置為不可寫。 然后,您的信號處理程序可以設置interrupted
標志,並將這些頁面設置為可寫。 這應該給你足夠的空間,使得恢復的代碼可以在不重新提升信號的情況下執行,遠遠足以檢查標志,並優雅地返回。 請注意,這是一次性的最后手段,除非您能找到一個好點,將這些保護頁面再次設置為不可寫。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.