簡體   English   中英

我如何使用堆棧但避免C ++中的堆棧溢出

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM