2015-11-05 77 views
-1

這個問題是基於C/C++內存分配的。當您在堆棧中請求更多空間時會發生什麼情況?

我讀到堆棧和堆之間的差異,有一件事讓我感到困惑。應該在堆中爲大對象分配內存,但也可以在堆棧中作爲局部變量進行分配。

從此線程(C/C++ maximum stack size of program)我瞭解堆棧是有限的,並且限制相對較低(最大7.4MB)。

我測試該限制與下面的程序:

#include <vector> 
int main() { 
std::vector<double> test; 

for (int i = 0; i < 5000000; i++){ 
    test.push_back(i); 
} 

return 0; 
} 

總分配的存儲器是8字節*(5.000.000)= 40MByte。 這似乎不會引發任何類型的錯誤。我閱讀了這個資源(https://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors),發現堆棧溢出可能會引發分段錯誤或總線錯誤。

所以我想,問題是:當你在堆棧中「分配」更多的內存時會發生什麼情況?

+6

DR; TL;它發生**堆棧溢出** – 101010

+1

'std :: vector'可能會將內存分配給堆,而不是堆棧。 – MikeCAT

+8

您不在測試堆棧分配,您正在測試堆分配。要測試堆棧分配,例如運行無限遞歸函數 - 您將得到本地錯誤的名稱 – Rostislav

回答

0

std::vector在堆上分配內存,而不是堆棧。如果你想測試粘性分配,最簡單的方法是使用一個程序,如:

#include <cstdio> 
int main(void) { 
    char temp[1024*1024*40] = {}; 
    printf("%s\n",temp); 
    return 0; 
} 

(NB印刷是必要的,以防止緩衝區被優化掉。)
這對分配40 MIB堆棧,併產生堆棧溢出(請參閱live)。

另一種方法是遞歸調用一個函數。例如:

unsigned factorial_times_2(unsigned n) { 
    unsigned result; 

    if (n<2u) result=1u; 
    result = n * (factorial_times_2(n-1u)/2u); 

    return result * 2u; 
} 
int main(void) { 
    return factorial_times_2(~0u)/2u; 
} 

這是經典的遞歸階乘函數的簡單修改(修改,因爲現代編譯器將使簡單階乘尾遞歸)。在運行時,它將嘗試使用40億個棧幀。堆棧溢出產生(見live)。


堆棧溢出意味着,正如您所預料的那樣,您超出了給予堆棧的內存。由於堆棧通常分配了自己的頁面,因此在堆棧外走出一個有效的映射內存地址。

因此,堆棧溢出通常會導致分段錯誤(就像上面的例子中發生的那樣)。在Windows上,它被稱爲訪問衝突。如果你不那麼幸運,它會破壞你的程序數據,直到以後你纔會發現。

0

溢出堆棧的行爲與平臺有關。官方條款可能是「未定義的行爲」,意思是任何事情都可能發生。

平臺不需要實現堆棧,儘管這是一種常用技術。一些平臺爲棧和堆設置了存儲器,並使它們彼此「成長」(繪製圖片)。所以如果堆棧溢出,它就開始在堆上寫,反之亦然。

某些平臺可能設置了硬件防護,並且當處理器訪問超出範圍的內存時,會生成硬件異常。操作系統將處理該異常。

另一個例子是您的程序開始寫入某種硬件設備,如USB控制器或磁盤驅動器控制器。

總之,堆棧溢出的行爲是平臺相關的,包括恢復(如果有的話)。

相關問題