C#中實值型別和參考型別

來源:互聯網
上載者:User

標籤:

概念:

1.實值型別:資料存放區在記憶體的堆棧中,從堆棧中可以快速地訪問這些資料,因此,實值型別表示實際的資料。

2.參考型別:表示指向儲存在記憶體堆中的資料的指標或引用(包括類、介面、數組和字串)。

 

C#中定義的實值型別包括原類型(Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚舉(enum)、結構(struct)

參考型別包括:類、數組、介面、委託、字串等。 

 

區別:

基本區別在於它們在記憶體中的儲存方式。實值型別只將值存放在記憶體中,這些實值型別都儲存在堆棧中。未經處理資料類型(如bool和int)都屬於此類型。而參考型別的記憶體單元中只存放記憶體堆中對象的地址,而對象本身放在記憶體堆中。如果引用的實值型別的值是null,則表示未引用任何對象。

堆和堆棧區別

堆和堆棧是兩個不同的概念,在記憶體中的儲存位置也不相同,

堆一般用於儲存可變長度的資料,如字串類型;

堆棧則用於儲存固定長度的資料,如整數型別的資料int(每個int變數佔用四個位元組)。由資料存放區的位置可以得知,當把一個值變數賦給另一個值變數時,會在堆棧中儲存兩個完全相同的值;而把一個引用變數賦給另一個引用變數,則會在堆棧中儲存對同一個堆位置的兩個引用,即在堆棧中儲存的是同一個堆的地址。在進行資料操作時,對於實值型別,由於每個變數都有自己的值,因此對一個變數的操作不會影響到其它變數;對於參考型別的變數,對一個變數的資料進行操作就是對這個變數在堆中的資料進行操作,如果兩個參考型別的變數引用同一個對象,實際含義就是它們在堆棧中儲存的堆的地址相同,因此對一個變數的操作就會影響到引用同一個對象的另一個變數。

 

 

為了更好地說明兩種類型之間的區別,借用如下的表格來說明。

  實值型別 參考型別
記憶體配置地點 分配在棧中 分配在堆中
效率 效率高,不需要地址轉換 效率低,需要進行地址轉換
記憶體回收 使用完後,立即回收 使用完後,不是立即回收,等待GC回收
賦值操作 進行複製,建立一個同值新對象 只是對原有對象的引用
函數參數與傳回值 是對象的複製 是原有對象的引用,並不產生新的對象
類型擴充 不易擴充 容易擴充,方便與類型擴充

 


註:GC(Garbage Collector,記憶體回收行程)是一種自動回收記憶體的機制,釋放已經不再使用的對象的記憶體空間。

在.NET平台中,我們的Managed 程式碼一般都不再關心記憶體的管理,一切都有CLR(Common language Runtime)去幫我們完成了。當我們開闢記憶體空間用來建立對象時,使用new關鍵字,這時CLR會分配一塊記憶體存放對象,大部分時候,我們都不用自己去釋放記憶體空間,而是由CLR在某個適當的時候幫我們釋放掉。 

  為什麼要GC? 

  1.建立新對象開闢記憶體空間,在使用完後需要釋放記憶體,提高效能

  2.避免開發人員直接操作記憶體,提高安全性

  GC(回收)過程 

  我們運行.NET程式後,OS Loader首先識別出IL(中繼語言),然後會載入CLR的核心庫,進行一系列的必要處理後,CLR來到我們編寫的代碼入口處執行。

  當我們的在代碼中使用new操作符建立class時,CLR便在叫作GC堆(GC Heap)的記憶體地區上分配一塊記憶體存放我們的對象,若對象的Size超過85K位元組時,考慮到效能原因,將對象建立在LOH(Large Object Heap)上而不是GC堆上【注1】,若我們在class中定義了解構函式來釋放非託管資源【注2】,則CLR會在一個叫做終結器隊列(Finalizer Queue)的地方添加一個指向該class的項。

  我們的程式在啟動並執行過程,在某個時候需要進行記憶體回收了【注3】,首先GC會暫時掛起所有線程,然後確定對象引用的roots【注4】,並根據參考關聯性建立出由roots出發可以達到的對象形成的對象圖,這些對象暫時還在使用,而那些已建立的卻不在對象圖中的對象則是不可達到的,也就是垃圾了,屬於要回收的對象。隨後將仍然使用的對象移動到存活期更久的地區【注5】,更改地區指標以回收對象,壓縮記憶體去除記憶體空隙,並修複對移動的仍存活對象的引用指標,對於有解構函式的對象,則第一次回收時不會回收,而是將其在終結器隊列中移除,並添加到另一個標為準備終止的對象列表中,另一個GC線程會調用此列表指向的對象的Finalize(),回收非託管資源,然後將項從列表中移除,下一次的GC才會真正回收掉該對象。

 

  注1:對象建立在Heap上的細節

  1): 為了更高效的進行GC,.NET將GC堆分成了3個代,Gen0,Gen1和Gen2。

  2): 這3個代只是邏輯上的劃分,在記憶體中,他們的地址是連續的。

  3): Gen0和Gen1之和的大小大約是16M(workstation GC模式下)和64M(server GC模式下)。

  4): 新建立對象Size小於85k位於Gen0上,大於85K的則建立在LOH上。

      注2:定義解構函式釋放非託管資源

  Finalize方法是用來釋放對象中使用的非託管資源,他是作為Dispose()方法的一種安全防護措施,即代碼中沒有顯示的調用Dispose()來釋放非託管資源時,GC時調用Finalize方法來釋放,Finalize方法中並不直接釋放非託管資源,而是調用Dispose(false)來釋放。自.NET2.0起,C#中不能直接override Finalize方法,是通過解構函式來實現,解構函式在IL中會被解釋為:

C#中實值型別和參考型別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.