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