淺談值類型和引用類型在堆和棧中的存儲一

首先,讓咱們來簡單瞭解一下什麼是「棧」(stack),什麼是「堆」(heap)。「棧」其實就是一種後入先出(LIFO)的數據結構。在咱們.NET Framework裏面,由CLR負責管理,咱們程序員不用去擔憂垃圾回收的問題;每個線程都有本身的專屬的「棧」。「堆」的存放就要零散一些,而且由 Garbage Collector(GC)執行管理,咱們關注的垃圾回收部分,就是在「堆」上的垃圾回收;其次就是整個進程共用一個「堆」。程序員

 

 

咱們先來記住兩條黃金法則:數據結構

1.引用類型老是被分配到「堆」上。函數

2.值類型老是分配到它聲明的地方:spa

   a.做爲引用類型的成員變量分配到「堆」上線程

   b.做爲方法的局部變量時分配到「棧」上指針

 

要真正理解上面的兩條黃金法則,還須要瞭解一下,「棧」和「堆」是如何工做的。首先如下面的這個方法爲例:code

public int AddFive(int pValue)
{
  int result; 
  result = pValue + 5; 
  return result;
}

1.方法AddFive()被壓入「棧」對象

2.緊接着方法參數pValue被壓入「棧」blog

3.而後是須要爲result變量分配空間,這時被分配到「棧」上。進程

4.最後返回結果

經過將棧指針指向 AddFive()方法曾使用的可用的內存地址,全部在「棧」上的該方法所使用內存都被清空,且程序將自動回到「棧「上最初的方法調用的位置。

 

 

下面咱們來看看,值類型的變量分配到「堆」上到狀況。

public class MyInt
{
    public int MyValue;
}

public MyInt AddFive(int pValue)
{
    var result = new MyInt();
    result.MyValue = pValue + 5;
    return result;
}

和前面同樣,線程開始執行函數,函數參數被壓入線程堆棧。

因爲 MyInt 爲引用類型,它被分配在「堆」上,而且由一個位於「棧」上的指針引用。

AddFive()函數執行完畢後,「棧」一樣會被清空。

 

最後,只剩下一個 MyInt 類被留在「堆」上(「棧」上再也沒有指向這個 MyInt 類的指針)!這個時候就須要GC機制來處理了。

 

好了,你們對「棧」和「堆」有必定的瞭解以後,下面讓咱們來稍微深刻一點,來看兩個例子。

public int ReturnValue()
{
    int x = 3; 
    int y = x;
    y = 4;
    return x;
}

返回值你們其實已經知道了吧,仍是3。這是爲何呢?這是由於,值類型,使用的就是值自己,其實在作int y = x的時候,就把3作了一份「拷貝」賦值給了y,而後在y = 4的時候,操做的是這個「拷貝」,並不會操做原來的3。

接下來咱們看另一個例子,MyInt仍是使用上面例子中使用過的MyInt類。

public int ReturnValue()
{
    var x = new MyInt();
    x.MyValue = 3; 
    MyInt y; 
    y = x;
    y.MyValue = 4; 
    return x.MyValue;
}

在這個代碼中,x.MyValue是否仍是會是3呢?是否y.MyValue仍是操做的3的「拷貝」呢?其實只要運行一下這個代碼,就能夠得出結果,x.MyValue仍是被修改爲了4。這是由於,當咱們使用引用類型時,咱們其實是在使用指向這些對象的地址,而不是直接使用這些對象自己。

 

好了,暫時就介紹到這裏,若是有什麼疑問,或者有誤的地方,歡迎你們指點和交流。

相關文章
相關標籤/搜索