值類型與引用類型變量探究

.Net將變量的類型分爲引用類型和值類型兩大類。使用int、double等數值類型所定義的變量屬於值類型,除此之外,枚舉類型和結構也屬於值類型。類類型的變量屬於引用類型,他們可以引用一個真實的對象。

.Net中的引用類型分爲:類類型、接口類型、數組類型和委託類型。

值類型變量與引用類型變量的內存分配模型是不一樣的,爲此先區分下兩種不同類型的內存區域:線程堆棧和託管堆

線程堆棧和託管堆

每個正在運行的程序都對應一個進程,在一個進程內部可以有一個或多個線程,每個線程都擁有一塊內存,稱爲“線程堆棧”,大小爲1M,用於保存自身的一些數據,比如線程函數中定義的局部變量、線程函數調用時傳送的參數值等,這部分內存區域的分配與回收不需要程序員干涉。如下代碼

void func()
{
    int i = 100;
    ........
    return;
}

CLR在執行函數func時會在線程堆棧中爲它的局部變量i分配一個4字節的空間,並初始化爲100,然後CLR執行剩餘的代碼,如果函數中還定義了其他局部變量,還會在線程堆棧中分配新的存儲空間給這些局部變量。

當CLR執行函數func的return語句時,函數執行結束,CLR將負責回收分配給此函數的局部變量的內存,這一工作是自動進行的,大多數情況下程序員是不必理會的。

值類型變量所佔用的內存單元是在線程堆棧中分配的。

另一塊內存區域稱爲“堆”,在.Net這種託管環境下,堆由CLR進行管理,所以稱爲“託管堆”。
當用new關鍵字創建對象的時候,分配給對象的內存單元就位於託管堆中。

引用類型變量引用的對象所佔的內存單元是在託管堆中分配的

引用類型變量的內存模型

測試代碼如下:

class MyClass
{
    public int Value;
    public int[] Numbers = new int[10];
}

static void Main(string[] args)
{
    MyClass obj;
    obj = new MyClass();
}

代碼中先是創建了一個引用類型變量obj,此時默認值爲null,沒有引用任何對象。下面用new關鍵字在託管堆中創建了一個NyClass類型的對象,此時obj的值爲對象的首地址。此時的對象內存模型如下圖所示。

 

引用類型變量obj生存於線程堆棧中,因爲它是Main方法的局部變量,而MyClass對象生存於託管堆中,obj所代表的線程堆棧中的內存單元保存的是託管堆中NyClass對象的首地址。

由於引用類型變量和它所引用的對象生存於不同的世界,因此這兩者其實是獨立的,引用類型變量被銷燬(比如定義它的方法執行結束時)並不意味它所引用的對象也會被銷燬,這一對象有可能會繼續生存一個相當長的時間。

如果是對象數組呢,它的內存模型是如何的呢?

MyClass[] objs;
objs = new MyClass[10];

創建完對象的內存模型如圖:

由於數組對象本身是引用類型,所有不管數組元素是值類型還是引用類型,它所佔用的內存都在託管堆上分配。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章