go語言通過goroutine提供了併發程式設計支援,goroutine是go執行庫的功能,而不是作業系統執行緒實現的,goroutine可以被理解成乙個使用者態的執行緒。
既然goroutine是由go執行庫管理的,那麼go執行庫也需要為每個goroutine建立並管理相應的棧空間,為每個goroutine分配的棧空間不能太大,goroutine開多時會浪費大量空間,也不能太小,會導致棧溢位。go語言選擇棧的棧空間管理的方式是,一開始給乙個比較小的空間,隨著需要自動增長。當goroutine不需要那麼大的空間時,棧空間也要自動縮小。
在go 1.3之前,go使用分段棧。
分段棧實現了一種不連續但是可以持續增長的棧,開始時,棧只有乙個段,當需要更多的棧空間時,會分配乙個新的段,和上乙個棧雙向鏈結。這樣,乙個棧就是由多個雙向鏈結的段所組成的。當新分配的段使用完畢後,新段會被釋放掉。
分段棧實現了棧的按需收縮,在增加新分段時也不需要對原有分段中的資料進行拷貝,使得goroutine的使用代價非常低廉。
分段棧的好處是可以按需增長,空間利用率比較高,然而分段棧在某些情況下也存在一定的瑕疵。當乙個段即將用盡,這時使用for迴圈執行乙個比較耗空間的函式,會導致函式執行時goroutine進行段的分配,而執行完成返回時,進行段的銷毀,這樣就會導致在迴圈**現多次棧的擴容和收縮,造成很大的效能損失,這種情況被稱作棧**(stack split)。
go 1.3推出了連續棧,連續棧使用了另外一種策略,不再把棧分成一段一段的,當棧空間不夠時,直接new乙個2倍大的棧空間,並將原先棧空間中的資料拷貝到新的棧空間中,而後銷毀舊棧。這樣當出現棧空間觸及邊界時,不會產生棧**的情況。
繼續假設當前棧空間即將用盡,並且需要在for迴圈中執行乙個比較消耗空間的函式。當該函式執行時,棧空間發生了擴容,變成原先2倍大小,函式執行完成一次後,棧空間的使用量縮小回執行前的大小,但是棧空間的使用量並沒有小於棧大小的1/4,不會觸發棧收縮,所以在整個for迴圈執行過程中,不會反覆觸發棧空間的收縮擴容。
相比於分段棧,連續棧避免了某些場景下棧空間的的頻繁伸縮。有一點需要注意的是,連續棧的收縮也是需要重新申請一段空間(原先的1/2大小),並進行棧拷貝操作的。
使用者空間棧 系統空間棧
使用者空間棧 系統空間棧 以下簡稱使用者棧 核心棧 1 使用者棧和核心棧的區別 核心在建立程序的時候,在建立task struct的同時,會為程序建立相應的堆疊。每個程序會有兩個棧,乙個使用者棧,存在於使用者空間,乙個核心棧,存在於核心空間。記住,程序對應的使用者棧和核心棧都是程序私有的。當程序在使...
八 棧的操作 棧空間
棧規則先進後出的影象未過程簡易圖 入棧push 暫存器 例如 push ax 將ax資料放入棧中 push 段暫存器 例如 push es 將es資料放入棧中 出棧pop 暫存器 例如 pop ax 將棧資料取出放入ax pop 段暫存器 例如 pop es 將棧資料取出放入段暫存器es 長例 mo...
共享空間的棧
當我們需要兩個棧的儲存資料的時候,可能會出現其中乙個棧不夠用,另外乙個棧又不經常使用的情況,可以試著把兩個棧合體。這是一種策略,在日常生活中也有類似的情況,比如情侶,有的情侶畢業了還是分開住,有的情侶可能會想一起租房子不是更好嘛,他好,我也好。typedef int elemtype typedef...