每一個虛擬機都有它本身的對象佈局,本文咱們將針對sscli源碼和windbg調試器來查看不一樣類型的.net對象佈局。編程
在.net虛擬機裏,每一個對象都須要保存這些信息:數組
- 對象的類型;
- 對象實例的成員屬性(field)值;
- hash值、鎖信息等其餘數據結構。
普通對象
在CLR裏,對象在託管代碼(managed code)和非託管代碼(unmanaged code)裏有不一樣的表現形式。在託管代碼裏,全部對象的基類Object類型是在 clr\src\bcl\system\Object.cs裏定義,而其在非託管世界裏,則複雜的多,由在clr\src\vm\object.h裏定義的Object類型,clr\src\vm\SyncBlk.h裏定義的ObjHeader等類型實現。對象在非託管代碼理的內存物理佈局以下圖所示:數據結構
- 在非託管代碼裏,對象實際上有兩個指針。
- object指針就是虛擬機返回給託管代碼的對象引用地址,從這個指針開始,託管代碼就能夠獲取到任何一個對象的類型以及成員變量信息。
- 而另一個指針objhead,其實是非託管代碼裏,每一個.NET對象實際的指針,在這個指針後面,包含了控制線程同步,甚至是COM Interop相關信息的SyncBlock索引,這個索引的做用咱們會在後文提到。由於索引只用到32位字節,因此在64位系統運行的時候,會加上一個填充用的DWORD以便補齊內存邊界。
- object指針後面緊跟的就是該對象所屬的類型:MethodTable,MethodTable顧名思義就是函數表,在.NET裏它就是對象類型的表明,在後文咱們也會詳細說明它。
- 類型信息後面就是每一個對象實例成員變量的值信息了,若是是成員變量是引用類型,那麼就保存被引用的對象的object指針(不是objhead),若是是值類型,好比說結構體,那麼就按照值類型的內存佈局,將變量值直接保存在對象的內存區域裏。

雖然.NET裏全部引用類型的對象都從Object類型裏繼承,一些特殊的對象,在CLR裏也在非託管代碼裏定義了一份不一樣的佈局,方便虛擬機的處理。編程語言
數組對象 - Array
在託管代碼裏,其在 clr\src\bcl\system\Array.cs 裏定義,在非託管代碼裏,其在 clr\src\vm\object.h 裏定義。之因此這樣作,是由於數組對象便可以保存引用類型,也能夠保存值類型,並且爲了方便程序訪問數組的長度,數組對象其實是將長度信息直接保存在內存裏了,以下圖是其內存佈局:函數
- 除了將長度信息直接保存到內存之外,若是是多維數組,則還會將各個緯度的上標和下標信息都保存到內存裏,這主要是支持向VB這樣的能夠修改數組上下標的編程語言設計的。
- 若是是引用類型,則會把成員元素的類型指針保存在數組裏;
- 若是是值類型,則直接保存成員元素的內容。

字符串對象
在託管代碼裏,其在 clr\src\bcl\system\String.cs 裏定義,在非託管代碼裏,其在 clr\src\vm\object.h 裏定義。佈局
- 由於在.NET裏字符串是不能修改的,能夠將其看成數組處理,因此.NET直接將字符串的長度保存在內存裏;
- 爲了方便非託管代碼處理字符串,每一個字符串最後以 NULL 結尾,固然字符類型是WCHAR,而不是CHAR,這也就是說.NET下面字符默認是UNICODE。
