.NET 類型(Types)的那些事

引言

您是.Net工程師?那 .NetFramework中的類型您知道有三大類嗎?(除了引用類型和值類型,還有?)

引用類型一定在“堆”上,值類型一定在“棧”上?

那引用類型在內存中的布局細節您又知道多少了?

?

.Net Framework 中的Types分類

?

09fig01

C# type categorization. 帶陰影的都是 C# 的內建類型關鍵字.

除了object and string(分別為System.Object System.String別名), 其他帶陰影的都是簡單的值類型.

下面是摘自《C#語言規范5.0》 –> 4.類型(page:77)

C# 語言的類型劃分為兩大類:值類型 (Value type) 和引用類型 (reference type)。

第三種類型是指針,只能用在不安全代碼中。

引用類型和值類型在內存中如何分配的呢?

這一塊我們將通過一小段代碼來講解,在講解前讓我們回顧下

引用類型 和值類型的賦值過程中在內存處理上的區別:

  • 把一個值類型a(定義如下int a=80;)賦給另外一個值類型b(int b;),即(b=a;)時,會把a的值拷貝一份給a,如下圖;

value_type

  • 把一個引用類型a(定義如下Employee a=new employee();)賦給另外一個引用類型b(Employee b;),即(b=a;)時,會把a的地址(引用)拷貝一份給a,即他們指向同一個地址;

reference_type1

開始代碼講解,首先看代碼如下:

Form myForm = new Form();
Size s = new Size (100, 100);          // struct = value type
Font f = new Font (“Arial”,10);        // class = reference type
myForm.Size = s;
myForm.Font = f;

注意代碼中 myForm.Size中的Size和myForm.Font的Font是Form類型的屬性(Property)不是類型(class type,代表某個類型)。

在.NetFramework中這樣的使用方式極其普遍,初學者不要混淆了這兩者。

講解代碼前給大家再提下知識點:

  • Size是Struct類型,當然就是值類型(ValueType)
  • Font是Class類型,當然就是引用類型(ReferenceType)

?

上面這段代碼的內存中的分配,示意圖:

image006

很清楚地看到

  • Size類型的s分配到了Stack上,而Front類型的f 和Form類型的myForm則分配在堆上。
  • 并且myForm的Font屬性引用到了Font類型f。
  • myForm的Size屬性有它自己的值(Width和Height),它是Size類型s的一個拷貝。

這里我們更清晰的看到了值類型和引用類型在值賦值過程中的區別

我們可以通過修改Font類型f的值,來修改myForm中的字體樣式,但不能通過修改s來修改myFrom的Size。

引用類型的Object內存布局基礎結構

image_thumb_2

上面這個圖展示的結構是通過分析源碼得出的:

  1. 首先ObjectHeader(在其所在的AppDomain中的那個Thread通過調用Monitor.Enter鎖了這個對象)
  2. 接下來是Method Table 指針(該指針指向AppDomain中聲明(定義)托管類型),如果程序集被加載到AppDomain neutral 中,那么所有的AppDomain中該類型實例的Method Table指針都一樣。CLR 類型系統的該基礎構建塊在托管代碼中都是可視的。(TypeHandle.Value 是一個IntPtr)
  3. 最后就是這部分就是該類型實例的值。

CLR object的這個實例對象的地址在垃圾回收時也有可能會發生變動。(具體參看GC中壓縮過程)

?

\sscli20\clr\src\vm\object.h

//
// The generational GC requires that every object be at least 12 bytes
// in size.   
#define MIN_OBJECT_SIZE     (2*sizeof(BYTE*) + sizeof(ObjHeader))

A .NET object has basically this layout:

class Object
{protected:MethodTable*    m_pMethTab;};
class ObjHeader
{private:// !!! Notice: m_SyncBlockValue *MUST* be the last field in ObjHeader.DWORD  m_SyncBlockValue;      // the Index and the Bits
};
Platform最小實例大小(bytes)
x8612 bytes = 2*4+4
x64 24 bytes = 2*8+8

?

引用類型的Object內存布局代表性結構

?

普通對象

?

012302077246530

數組對象 - Array

012302218801605

字符串對象

012302322553069

?

Boxing,小心您的值類型不經意間被裝箱

?

int a=1;
object b=a;

這段代碼大家都知道會發生裝箱,裝箱后原來的值類型會有哪些變化?看下裝箱和拆箱的步驟:

裝箱:
對值類型在堆中分配一個對象實例,并將該值復制到新的對象中。按三步進行。
第一步:新分配托管堆內存(大小為值類型實例大小加上一個方法表指針和一個SyncBlockIndex)。
第二步:將值類型的實例字段拷貝到新分配的內存中。
第三步:返回托管堆中新分配對象的地址。這個地址就是一個指向對象的引用了。
有人這樣理解:如果將Int32裝箱,返回的地址,指向的就是一個Int32。我認為也不是不能這樣理解,但這確實又有問題,一來它不全面,二來指向Int32并沒說出它的實質(在托管堆中)。
拆箱:
檢查對象實例,確保它是給定值類型的一個裝箱值。將該值從實例復制到值類型變量中。
有書上講,拆箱只是獲取引用對象中指向值類型部分的指針,而內容拷貝則是賦值語句之觸發。我覺得這并不要緊。最關鍵的是檢查對象實例的本質,拆箱和裝箱的類型必需匹配,這一點上,在IL層上,看不出原理何在,我的猜測,或許是調用了類似GetType之類的方法來取出類型進行匹配(因為需要嚴格匹配)。

那么給你個自定義結構體,你還清楚什么情況會被裝箱嗎?

參考《防止裝箱落實到底,只做一半也是失敗》

附加

為方便大家查看源碼,這里提供一個源碼索引表

SSCLI文件索引

ItemSSCLI Path
AppDomain\sscli\clr\src\vm\appdomain.hpp
AppDomainStringLiteralMap\sscli\clr\src\vm\stringliteralmap.h
BaseDomain\sscli\clr\src\vm\appdomain.hpp
ClassLoader\sscli\clr\src\vm\clsload.hpp
EEClass\sscli\clr\src\vm\class.h
FieldDescs\sscli\clr\src\vm\field.h
GCHeap\sscli\clr\src\vm\gc.h
GlobalStringLiteralMap\sscli\clr\src\vm\stringliteralmap.h
HandleTable\sscli\clr\src\vm\handletable.h
InterfaceVTableMapMgr\sscli\clr\src\vm\appdomain.hpp
Large Object Heap\sscli\clr\src\vm\gc.h
LayoutKind\sscli\clr\src\bcl\system\runtime\interopservices\layoutkind.cs
LoaderHeaps\sscli\clr\src\inc\utilcode.h
MethodDescs\sscli\clr\src\vm\method.hpp
MethodTables\sscli\clr\src\vm\class.h
OBJECTREF\sscli\clr\src\vm\typehandle.h
SecurityContext\sscli\clr\src\vm\security.h
SecurityDescriptor\sscli\clr\src\vm\security.h
SharedDomain\sscli\clr\src\vm\appdomain.hpp
StructLayoutAttribute\sscli\clr\src\bcl\system\runtime\interopservices\attributes.cs
SyncTableEntry\sscli\clr\src\vm\syncblk.h
System namespace\sscli\clr\src\bcl\system
SystemDomain\sscli\clr\src\vm\appdomain.hpp
TypeHandle\sscli\clr\src\vm\typehandle.h

更多源碼參考http://www.projky.com/dotnet

參考

?

The Truth About .NET Objects And Sharing Them Between AppDomains

Six important .NET concepts: Stack, heap, value types, reference types, boxing, and unboxing

Shared Source Common Language Infrastructure

[翻譯經典文章]深入.NET Framework內部, 看看CLR如何創建運行時對象的

.NET對象的內存布局

托管堆與垃圾收集

C# 裝箱和拆箱[整理]

mdsn?類型詳解(Jit and Run)

轉載于:https://www.cnblogs.com/HQFZ/p/4638794.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/397714.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/397714.shtml
英文地址,請注明出處:http://en.pswp.cn/news/397714.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

幾種去除數組中重復元素的方法、數組去重

工作中遇到的一個問題&#xff0c;就是去除數組中重復的元素&#xff0c;記錄一下幾種有效的方法&#xff1a; 第一種思路&#xff1a;遍歷要刪除的數組arr, 把元素分別放入另一個數組tmp中&#xff0c;在判斷該元素在arr中不存在才允許放入tmp中。 <!DOCTYPE html> <…

MongoDB學習使用

一、什么是MongoDB&#xff1f; MongoDB是一個高性能&#xff0c;開源&#xff0c;無模式的文檔型數據庫&#xff0c;是當前NoSql數據庫中比較熱門的一種。它在許多場景下可用于替代傳統的關系型數據庫或鍵/值存儲方式&#xff0c; NoSql&#xff0c;全稱是 Not Only Sql,指的是…

域賬號更改密碼之后代理需要重新配置

在使用域賬號的時候&#xff0c;如果需要配置賬戶和密碼&#xff0c;那么最好記錄下來&#xff0c;否則將來找不到就很尷尬了。 我遇到的問題是&#xff0c;因為在另外一臺電腦配置了域賬號&#xff0c;用來聯網&#xff0c;提供網絡給visual studio 1.Firefox 這個代理的賬號…

wcf精通1-15

隨筆- 197 文章- 0 評論- 3407 十五天精通WCF——第一天 三種Binding讓你KO80%的業務 轉眼wcf技術已經出現很多年了&#xff0c;也在.net界混的風生水起&#xff0c;同時.net也是一個高度封裝的框架&#xff0c;作為在wcf食物鏈最頂端的我們所能做的任務已經簡單的不能再簡單…

python如何實現共享報表系統_使用python來實現報表自動化-阿里云開發者社區

xlwt 常用功能xlrd 常用功能xlutils 常用功能xlwt寫Excel時公式的應用xlwt寫入特定目錄(路徑設置)xlwt Python語言中&#xff0c;寫入Excel文件的擴展工具。可以實現指定表單、指定單元格的寫入。支持excel03版到excel2013版。使用時請確保已經安裝python環境。百度百科xlrd Py…

去除inline-block元素間間距的N種方法

這篇文章發布于 2012年04月24日&#xff0c;星期二&#xff0c;22:38&#xff0c;歸類于 css相關。 閱讀 147771 次, 今日 52 次 by zhangxinxu from http://www.zhangxinxu.com 本文地址&#xff1a;http://www.zhangxinxu.com/wordpress/?p2357 一、現象描述 真正意義上的in…

Docker深入淺出2

Docker系統架構 Docker使用客戶端-服務端&#xff08;c/s&#xff09;架構模式&#xff0c;使用遠程api來管理和創建Docker容器。 docker容器通過Docker鏡像來創建。 容器與鏡像的關系類似于面向對象編程中的對象與類的關系 Docker面向對象容器對象鏡像類加速器配置&#xff1a…

mysql安裝包下載密碼_MySQL解壓包的安裝與下載的圖文教程

這篇文章主要為大家詳細介紹了mysql解壓包的安裝基礎教程&#xff0c;具有一定的參考價值&#xff0c;感興趣的小伙伴們可以參考一下由于換了新電腦&#xff0c;所以的環境都要到新電腦去配置。突然發現mysql的配置忘了&#xff0c;然后百度又重新來一遍。特地寫一篇文章記錄一…

php 扒取網頁數據

扒取方法 public function index(){$url http://www.dytt8.net/;// $url Public/txt/movies.txt;$content file_get_contents($url);$content iconv("gb2312", "utf-8//IGNORE",$content);$reg "|<div class\"co_content2\">(.*…

多維DP UVA 11552 Fewest Flop

題目傳送門 1 /*2 題意&#xff1a;將子符串分成k組&#xff0c;每組的字符順序任意&#xff0c;問改變后的字符串最少有多少塊3 三維DP&#xff1a;可以知道&#xff0c;每一組的最少塊是確定的&#xff0c;問題就在于組與組之間可能會合并塊&#xff0c;總塊數會-1。…

多表聯合查詢

關聯數據庫字典表的多表聯合查詢 inner join…on 自動連接 需要用到表的所有信息時&#xff0c;可以用以下兩種方法 1) left join…on… 左連接 &#xff08;以左為準&#xff0c;右邊沒有NULL代替&#xff09; 2) right join…on… 右連接&#xff08;以右為準&#xff…

python elasticsearch update_使用python的elasticsearch部分更新

我有以下格式的elasticsearch文檔。我需要部分更新“x”字段并在其中添加python dict。{"_index": "gdata34","_type": "gdat","_id": "328091-72341-118","_version": 1,"_score": 1,"…

32位與64位注冊表

如果32位系統OFP的注冊表路徑是 HKEY_LOCAL_MACHINE\SOFTWARE\Bohemia Interactive\ 那么在64系統里就應該是 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Bohemia Interactive\ 多了一級Wow6432Node轉載于:https://www.cnblogs.com/zhang-pengcheng/p/4712135.html

http 請求頭和響應頭

客戶端發送請求過程帶著的數據&#xff1a; 1.請求地址 2.請求方式 3.請求頭 request headers 4.請求參數 https://www.juhe.cn/ 130.... 1a2b....pei 服務端響應給客戶端的信息&#xff1a; 1.響應內容 2.響應報文/響應頭部 response headers a 響應頭 b 響應體 3.http狀…

[算法]-排序算法之希爾排序

希爾排序算法思想 希爾排序的實質就是分組插入排序&#xff0c;該方法又稱縮小增量排序.基本思想是&#xff1a;先將整個待排元素序列分割成若干個子序列&#xff08;由相隔某個“增量”的元素組成的&#xff09;分別進行直接插入排序&#xff0c;然后依次縮減增量再進行排序&a…

python tkinter button顏色變不了_tkinter多按鈕顏色變化

我使用tkinter創建一個8x8按鈕矩陣&#xff0c;當按下單個按鈕時&#xff0c;它會添加到最終列表中(例如finalList((0,0)&#xff0c;(5,7)&#xff0c;(6,6)&#xff0c;…)&#xff0c;允許我快速創建8x8(x&#xff0c;y)坐標圖像。我已經創建了一個帶有按鈕的窗口&#xff0…

應用spss可靠性分析軟件

問卷調查的可靠性分析 一、概念&#xff1a; 信度是指依據測驗工具所得到的結果的一致性或穩定性&#xff0c;反映被測特征真實程度的指標。一般而言&#xff0c;兩次或兩個測驗的結果愈是一致。則誤差愈小&#xff0c;所得的信度愈高&#xff0c;它具有下面特性&#xff1a;1、…

springmvc中的單例問題

1&#xff0c;springmvc實際上是基于一個叫做DispatcherServlet的servlet的。servlet按照以往的學習經驗&#xff0c;他是單事例多線程的。 Servlet生命周期 1.裝載Servlet。這項操作一般是動態執行的。然而&#xff0c;Server通常會提供一個管理的選項&#xff0c;用于在Serve…

設計模式 -- 亨元模式(FlyWeight Pattern)

用來盡可能減少內存使用量&#xff0c;適用于存在大量重復對象的場景&#xff0c;達到對象共享&#xff0c;避免創建過多對象的效果&#xff0c;提升性能&#xff0c;避免內存溢出。 定義&#xff1a; 使用共享對象有效支持大量細粒度對象。 適用場景&#xff1a; 系統中存在大…

python3.6使用mysql_Python之——Python3.6連接MySQL

只安裝了Python是不能連接數據庫的&#xff0c;還要安裝Python連接MySQL的相關類庫&#xff0c;Python2.7連接MySQL的類庫很多&#xff0c;MySQL官方最新支持的Python為Python3.4.&#xff0c;如下圖所示&#xff1a;那么&#xff0c;在Python3.6上如何實現連接MySQL的功能呢&a…