標籤:實值型別 參考型別 記憶體 棧 堆
C# 中堆與棧的淺記
什麼是堆和棧?
簡言之,堆和棧是駐留在記憶體中的地區,它們的作用是協助我們執行代碼。在.Net Framework 環境下,當我們的代碼執行時,記憶體中的堆和棧便儲存了這些代碼,並包含了代碼執行所需要的全部資訊。
這樣說來還是有些抽象,那麼,在堆和棧中究竟都儲存了些什麼呢?概括說來就是四類資料:
1、值類型資料
2、參考型別資料
3、指標
4、指令
下面對上述四類資料做以簡單介紹。我們知道,C#中的資料類型分為兩種,分別是值類型和參考型別。值類型資料直接在記憶體中的一個位置儲存它們自身的內容(值);參考型別資料在記憶體中的一個位置儲存指向記憶體中其它某個位置的地址,而在這個地址所指的位置中儲存內容(值)。
對於指標,我們在.Net Framework環境中不會顯示的使用指標,它們由CLR來管理。指標本身就是一個記憶體位址,它指向另一個記憶體位置。它的值就是一個記憶體位址或者為空白(null)。
指令指的就是執行該方法的指令,當方法執行時需要在棧上為之分配空間。
那麼,上述四類資料在堆與棧中是如何分配儲存的?或者我們還可以把關心的範圍再縮小一下,值類型資料與參考型別資料,它們是如何分配的?
規則:
1、參考型別資料總是存放在堆中;
2、值類型資料如果在方法體中被聲明,那麼它將存放在棧上;如果它作為參考型別的成員被聲明,那麼它將存放在堆中。
結合上面的兩條規則,讓我們分別來看一下堆與棧的不同之處。
在記憶體中,棧負責儲存代碼執行的路徑(調用路徑)。當我們的代碼開始調用一個方法時,首先將放置一段編碼指令到棧上,接下來再放置方法的參數,然後當代碼執行到方法體中聲明變數的位置,這些變數將被進棧至棧頂(注意,這裡指的是值類型資料,第一種情況)。截止到這裡,在方法體中被聲明的值類型資料,它們被存放在了棧上。當方法執行完成,方法的結果被返回,此時所有在棧上的該方法所使用的記憶體空間都被清空,程式將自動回到棧上最初方法調用的位置。這也告訴了我們一點,棧是自我維護的,記憶體自動維護棧,不存在記憶體回收問題。
第二種情況,當代碼執行到在方法體中被聲明的參考型別資料的位置,參考型別資料將在堆上被建立,與此同時在棧上產生一個指向這個堆的指標,這個指標就存放在棧上。當方法執行結束後,棧上的相關資訊被清除,但是,此時將剩下孤獨的參考型別資料參數在堆中,這就是記憶體回收產生的原因。注意,記憶體回收是非常耗費效能的,這就是為什麼我們要特別注意棧和堆的使用的原因。
以上內容是自己對於C#之中堆與棧的一個基本而又淺顯的理解,後續還會繼續深入思考,繼續挖掘堆與棧的內容。