日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#中值类型和引用类型

發布時間:2025/3/20 C# 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#中值类型和引用类型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C#中值類型和引用類型

http://www.cnblogs.com/123clb/archive/2011/03/03/1969712.html

概念:

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平臺中,我們的托管代碼一般都不再關心內存的管理,一切都有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中會被解釋為:

protected?override?void?Finalize()
{
????
try
????{
????????
//執行自定義資源清理操作
????}
????
finally
????{
????????
base.Finalize();
????}
}

  默認情況下,一個類是沒有析構函數的,那么在GC時是不會調用其Finalize()方法的。

  注3:GC發生的時機

  1)當Gen0的內存使用達到一個閾值時,將引發Gen0的GC,同理Gen1達到時,會Gen0和Gen1同時GC,若Gen2達到時,則會引發Full GC

  2)Windows報告內存不足時

  3)調用GC.Collect時

  4)其他情況:CLR卸載AppDimain,物理內存不足等?

?  注4:確定對象引用根

  對象的引用根主要來自于:FInalize Queue,CPU寄存器中的對象指針,全局對象、靜態變量、局部對象、函數調用參數等。

  注5: GC時對象的轉移

  1)Gen0 GC時,會將Gen0中存活的對象整體移動到Gen1中,然后壓縮Gen1,使Gen1中的內存連續,同理Gen1中移動到Gen2。

?

  2)Gen2 GC時,此時發生的GC也稱為Full GC,會回收整個Heap上的對象,Gen2上的對象將不再移動,而是壓縮內存空間。

  3)LOH中的對象在Full GC時被回收,但其內存不會被壓縮,而是使用一個空閑列表free list記錄LOH中的空閑空間,對釋放出來的空間進行管理。

  4)若對象是pinned object,則此對象不能被移動, 會造成內存碎片。


總結

以上是生活随笔為你收集整理的C#中值类型和引用类型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。