首先,讓我們來簡單了解一下什麼是“棧”(stack),什麼是“堆”(heap)。“棧”其實就是一種後入先出(LIFO)的數據結構。在我們.NET Framework裡面,由CLR負責管理,我們程序員不用去擔心垃圾回收的問題;每一個線程都有自己的專屬的“棧”。“堆”的存放就要零散一些,並且由 Garbage Collector(GC)執行管理,我們關注的垃圾回收部分,就是在“堆”上的垃圾回收;其次就是整個進程共用一個“堆”。
我們先來記住兩條黃金法則:
1.引用類型總是被分配到“堆”上。
2.值類型總是分配到它聲明的地方:
a.作為引用類型的成員變量分配到“堆”上
b.作為方法的局部變量時分配到“棧”上
要真正理解上面的兩條黃金法則,還需要了解一下,“棧”和“堆”是如何工作的。首先以下面的這個方法為例:
AddFive(= pValue +
1.方法AddFive()被壓入“棧”
2.緊接著方法參數pValue被壓入“棧”
3.然後是需要為result變量分配空間,這時被分配到“棧”上。
4.最後返回結果
通過將棧指針指向 AddFive()方法曾使用的可用的內存地址,所有在“棧”上的該方法所使用內存都被清空,且程序將自動回到“棧“上最初的方法調用的位置。
下面我們來看看,值類型的變量分配到“堆”上到情況。
MyInt AddFive( result = = pValue +
和前面一樣,線程開始執行函數,函數參數被壓入線程堆棧。
由於 MyInt 為引用類型,它被分配在“堆”上,並且由一個位於“棧”上的指針引用。
AddFive()函數執行完畢後,“棧”同樣會被清空。
最後,只剩下一個 MyInt 類被留在“堆”上(“棧”上再也沒有指向這個 MyInt 類的指針)!這個時候就需要GC機制來處理了。
好了,大家對“棧”和“堆”有一定的了解之後,下面讓我們來稍微深入一點,來看兩個例子。
x = y ==
返回值大家其實已經知道了吧,還是3。這是為什麼呢?這是因為,值類型,使用的就是值本身,其實在做int y = x的時候,就把3做了一份“拷貝”賦值給了y,然後在y = 4的時候,操作的是這個“拷貝”,並不會操作原來的3。
接下來我們看另外一個例子,MyInt還是使用上面例子中使用過的MyInt類。
= ==
在這個代碼中,x.MyValue是否還是會是3呢?是否y.MyValue還是操作的3的“拷貝”呢?其實只要運行一下這個代碼,就可以得出結果,x.MyValue還是被修改成了4。這是因為,當我們使用引用類型時,我們實際上是在使用指向這些對象的地址,而不是直接使用這些對象本身。
好了,暫時就介紹到這裡,如果有什麼疑問,或者有誤的地方,歡迎大家指點和交流。