2010-04-17 101 views
10

Linux中的進程的大小stack是否有限制?它是否僅僅依賴於機器的RAM? 我想知道這是爲了限制遞歸調用函數的深度。Linux中進程的堆棧大小是否有限制

謝謝。

+0

你總是可以一起快速測試,看看堆棧有多深。 CountDepth(int d){CountDepth(d + 1); } – Martin 2010-04-17 00:21:58

+2

@Martin:雖然當你真的在函數中做某些事情時,「深度」會降低,而變量。 – GManNickG 2010-04-17 00:25:06

+0

這是真的,但這是一個很好的估計。如果你真的想要的話,你可以計算臨時變量和方法參數中使用的位數,並準確地爲給定函數計算 – Martin 2010-04-17 02:55:13

回答

22

堆棧通常受限於資源限制。您可以看到默認的設置是使用ulimit -a安裝什麼:

stack size    (kbytes, -s) 8192 

(這表明我的是8MB,這是巨大的)。

如果您刪除或增加了該限制,您仍然無法使用機器中的所有RAM用於堆棧 - 堆棧從進程地址空間頂部附近的點向下增長,並且在某些指向它將運行到您的代碼,堆或加載庫。

+1

「在某些時候它會運行到你的代碼,堆或加載庫」我懷疑這是否會成爲64位系統上的問題,如Linux x86_64? – 2015-02-06 01:51:04

+0

@SamWatkins:好的 - 這個答案是5年前寫的,並且是在32位環境中。 – caf 2015-02-06 11:24:20

+0

如果[ABI](http://www.sco.com/developers/devspecs/abi386-4.pdf)是可信的,則這對'i386'不正確。其中,堆棧位於其他所有內容之下,理論上可以增長到超過128MiB。在['AMD64' ABI](https://www.uclibc.org/docs/psABI-x86_64.pdf)中,它在'128GiB'標記下增長,就在共享庫下。所以它理論上可以覆蓋代碼/數據,但只能覆蓋主程序或堆。 – 2016-09-25 21:06:49

5

該限制可以由管理員設置。

請參閱man ulimit

有可能是你不能跨越的默認值。如果你不得不擔心堆棧限制,我會說你需要重新考慮你的設計,也許寫一個迭代版本?

+1

或者只是編寫一個使用手動管理堆棧而不是函數調用堆棧的遞歸版本。 – 2010-04-17 00:59:29

+2

@Roger Pate:這基本上是迭代版本。 – slebetman 2013-04-29 01:59:23

3

它很大程度上取決於您所在的體系結構(32位或64位)以及您是否是多線程的。

默認情況下,在單線程進程中,即在exec()時由操作系統創建的主線程,堆棧通常會增長,直到在地址空間中遇到其他東西。這意味着在32位機器上通常可以擁有1G的堆棧。

但是,在多線程32位進程中絕對不是這種情況。在多線程處理中,堆棧共享地址空間,因此需要分配地址空間,因此它們通常會獲得少量地址空間(例如1M),因此可以在不耗盡地址空間的情況下創建多個線程。

因此,在一個多線程的進程中,它是小而有限的,在一個單線程的進程中,基本上直到你在地址空間(默認的分配機制試圖確保不會太快發生)碰到別的東西。

在64位機器中,當然還有更多的地址空間可供使用。

在任何情況下,您總是可以用完虛擬內存,在這種情況下,您將獲得SIGBUS或SIGSEGV或其他東西。

0

本來評論公認的答案,但顯然我需要更多的代表....

真正的堆棧溢出可能是微妙的,並不總是引起任何錯誤消息或警告。我只是有一種情況,唯一的症狀是套接字連接會失敗,出現奇怪的SSL錯誤。其他一切正常。線程可以malloc(),搶鎖,與數據庫交談等。但是新連接在SSL層失敗。

由於GnuTLS中的堆棧軌跡很好,所以我對這個真正的原因感到非常困惑。在花費大量時間試圖弄清楚之後,幾乎將這些痕跡報告給了他們的團隊。

最終發現stacksize被設置爲8Mb,並立即提升後問題消失。將堆疊降回8Mb帶來了問題(ABA)。

所以,如果你正在排除什麼似乎是奇怪的套接字錯誤,沒有任何其他警告或未初始化的內存錯誤....它可能是堆棧溢出。

+1

不應該堆棧後面有未映射/不可寫的塊(上面和下面),以防止這種大屠殺?如果我是正確的,堆棧如何溢出不會導致SEGV或類似故障?我建議你的錯誤的原因可能是別的,堆棧變化通過巧合(準heisenbug)來修正它。 – 2015-02-06 01:52:16

相關問題