程序設計中,堆和棧比較重要。棧存取速度大於堆,而且編譯器可以修改棧大小,這個值可以隨意設置嗎?

程序設計中,堆和棧(又稱堆棧)比較重要。都知道棧存取速度大於堆,而且編譯器可以修改棧大小(vc默認1M).請問可以隨意設置么?既然快速,為什麼編譯器默認那麼小,是不是底層cpu也有支持相應機制呢?百度了很久沒一個說到點子上~~不停解釋堆與棧的區別以及棧可修改。對於能改多大,是否與操作系統或者底層cpu有關,沒一個人知道~~請教知乎大神~


事實上,當我們不考慮高速緩存的情況時,堆和棧的速度絕對沒有差別。當我們考慮高速緩存的時候,由於棧是當前代碼段最常訪問的內存,於是其位於高速緩存上的概率幾乎可達100%。也就是說訪問它基本不會出現cache miss(不要用特例反駁,因為我們討論的是一般情況)。而堆一般來說都會出現cache miss,雖然也可以通過適當的編碼方式減少cache miss,但總體來說是無法和棧比的。這就是棧快而堆慢的原因。

如果已經了解前面的陳述,你希望的通過擴大棧來提升你的程序的性能基本上沒用,因為高速緩存在一台指定的機器上是定死的。


你說的那個默認1M的棧,應該指的是call stack(函數調用使用的棧)。這個棧用來存放函數調用時所傳遞的參數(並非所有參數都通過棧傳遞),棧指針,return address,寄存器的備份,還有每層函數的local variable。

1M大多數情況都是夠用的,如果用完可能會發生非法訪問等錯誤。可能會用完1M的情況:某個被調用的函數申請了一個很大的local variable,比如直接在棧上開個大數組之類的;還有就是遞歸調用,遞歸層數多了後很容易就用完1M。所以遞歸一般不要亂用。


1:在絕大多數情況下,棧內存的訪問不應該比堆內存快或慢。

2:我個人推測:所謂棧比堆快的說法,可能指的就是少了一次malloc/free的過程而已。

3:進程棧內存可以通過修改內核參數來設置,當然不是無限制的大的,會有個上限(好像是在xxx/limits.conf看的?忘了)。

4:現在進程棧一般默認是8M吧?其實只要不濫用遞歸,或者alloca/vla,絕大部分情況下都是夠用的。

5:即使沒超過內核限制,一般也不宜開得很大,不然會影響並行進程數。而且進程啟動時間應該也會略為降低。當然,如果是專用的伺服器系統,問題倒不很嚴重。


需要的話可以使用alloca(),會把空間放在棧上,還不用自己釋放,函數結束自動釋放。不過一定要小心使用。

---------------------------------------------------

我才發覺,如果你要棧的空間,貌似只能用alloca(),如果棧空間不夠用可以嘗試增加,看這個帖子

gcc - Change stack size for a C++ application in Linux during compilation with GNU compiler


棧就是OS固定給你分配好的一個內存空間(而且還可能是物理連續的),你自己隨便用就行。

堆上的內存要申請的比如C裡面的malloc,C++裡面的new,這時候要找操作系統申請內存,用完了還得還回去,當然就麻煩了。

把棧開大也不是不可以,但是會造成上下文切換的時候變慢咯。


百度不行google試試?這真的不是黑百度么……


我記憶中的棧在x86上面,棧主要是由ss和sp訪問的,在32位保護模式下,ss寄存器存的是一個段選擇子,選擇子是一個數字,通過IDT(局部描述符表)或者GDT(全局描述符表)選擇一個段描述符,描述符裡面的信息包含該段的取值範圍和大小。這就是我所知道的和cpu有關的,段的大小上限為4GB(即使你的電腦沒有4G的內存)。之所以說棧主要是用ss和sp訪問是因為其他定址方式訪問棧段是完全可以的,不過push和pull指令壓棧和出棧看起來要簡單一點,至於有沒有速度優勢?我猜應該沒有吧,否則處理器的構架設計師會被吐槽的。至於為什麼操作系統會限制棧段的大小(一般情況下,x86的操作系統控制段大小應該位是通過描述符控制的),因為程序使用棧的空間都不會使用太大的棧空間,因為std調用協議是這樣的:(我瞎編的,不要當真) 函數調用時,右邊的參數先入棧。於是每次調用其他函數時,先push各個參數,然後call,call指令會只壓入eip或者一起壓入cs:eip,取決於短跳轉還是長跳轉。然後進入函數之後,函數開始聲明局部變數,這些變數就被壓棧,緊跟在eip之後,你都用不了多大的棧,多多的分配給你不是浪費嗎。並沒有資料顯示棧會比堆快,除了申請的時候慢了一點之外。當然可能會和高速緩存命中率有關。

VC6.0中修改堆棧大小的方法:

1). 選擇 "Project-&>Setting".

2). 選擇 "Link".

3. 選擇 "Category"中的 "Output".

4. 在 "Stack allocations"中的"Reserve:"中輸棧的大小,例如: 32768

在VS2010中設置堆棧大小的方法為:

1). 選擇 "項目-&>屬性".

2). 選擇 "鏈接器".

3. 選擇 "系統".

4. 在 "堆棧保留大小"中輸棧的大小,例如: 32768 。


在有些CPU中會有硬體棧,所以比軟體堆快。棧用於中斷或調用保存上下文,堆用於申請使用內存,用途不一樣。


理論上棧的大小可以設置的很大~

堆和棧都是一樣嗯內存,存取速度沒區別~

棧是進城運行所在的內存空間,臨時變數 函數返回地址 參數之類的會放在棧上,堆特指動態申請的內存用的空間

其實也不太懂正常程序怎麼運行的,因為一直接觸的都是linux內核態的東西,內核態進程,棧固定只有8k這麼大~


棧和堆,都是內存中的一塊區域,沒有哪個更快的說法(有些書上說的棧比堆效率高,是由於存取演算法決定的效率差異,棧存取的步驟比堆少)。

區別是棧由編譯器分配,比如你定義了一個局部變數,就自動分配到棧上了;而堆是程序員來分配,C語言里就是通過malloc等來顯式的分配內存用於存儲數據。


操作系統說的堆棧和演算法里的堆棧不是一個東西


推薦閱讀:

GPU編譯器開發怎麼樣,前景如何?
Android 中的 LLVM 主要做什麼?
C++特性問題?
編譯器本身是如何進行測試的?
如何學習 clang和LLVM(有關於源代碼閱讀),需要哪些知識?

TAG:操作系統 | 編程 | C編程語言 | 編譯器 |