CoreCLR源码探索(一) Object是什么
.Net程序員們每天都在和Object在打交道
如果你問一個.Net程序員什么是Object,他可能會信誓旦旦的告訴你"Object還不簡單嗎,就是所有類型的基類"
這個答案是對的,但是不足以說明Object真正是什么
在這篇文章我們將會通過閱讀CoreCLR的源代碼了解Object在內存中的結構和實際到內存中瞧瞧Object
Object在內存中的結構
為了便于理解后面的內容,我先用一張圖說明Object在內存中的結構
.Net中的Object包含了這三個部分
- 指向頭部的指針 
- 指向類型信息的指針 
- 字段內容 
微軟有一張更全的圖(說明的是.Net Framework的結構,但是基本和.Net Core一樣)
frameborder="0" scrolling="no" style="border-width: initial; border-style: none; width: 550px; height: 589px;">
Object的源代碼解析
Object的定義(摘要)
源代碼:?https://github.com/dotnet/coreclr/blob/master/src/vm/object.h
PTR_MethodTable的定義,DPTR是一個指針的包裝類,你可以先理解為MethodTable*的等價
源代碼:?https://github.com/dotnet/coreclr/blob/master/src/vm/common.h
在Object的定義中我們只看到了一個成員,這個成員就是指向類型信息的指針,那其他兩個部分呢?
這是獲取指向頭部的指針的函數,我們可以看到這個指針剛好放在了Object的前面
PTR_ObjHeader GetHeader(){LIMITED_METHOD_DAC_CONTRACT; ? ?return dac_cast<PTR_ObjHeader>(this) - 1; }這是獲取字段內容的函數,我們可以看到字段內容剛好放在了Object的后面
PTR_BYTE GetData(void){LIMITED_METHOD_CONTRACT;SUPPORTS_DAC; ? ?return dac_cast<PTR_BYTE>(this) + sizeof(Object); }我們可以看到Object中雖然只定義了指向類型信息的指針,但運行時候前面會帶指向頭部的指針,并且后面會帶字段內容
Object在內存中擁有不定的長度,并且起始地址是分配到的內存地址+一個指針的大小
Object結構比較特殊,所以這個對象的生成也需要特殊的處理,關于Object的生成我將在后面的篇幅中介紹
Object中定義的m_pMethTab還保存了額外的信息,因為這是一個指針值,所以總會以4或者8對齊,這樣最后兩個bit會總是為0
.Net利用了這兩個閑置的bit,分別用于保存GC Pinned和GC Marking,關于這里我也將在后面的篇幅中介紹
ObjHeader的源代碼解析
ObjHeader的定義(摘要)
源代碼:?https://github.com/dotnet/coreclr/blob/master/src/vm/syncblk.h
m_alignpad是用于對齊的(讓m_SyncBlockValue在后面4位),值應該為0
m_SyncBlockValue的前6位是標記,后面26位是對應的SyncBlock在SyncBlockCache中的索引
SyncBlock的作用簡單的來說就是用于線程同步的,例如下面的代碼會用到SyncBlock
ObjHeader只包含了SyncBlock,所以你可以看到有的講解Object結構的文章中會用SyncBlock代替ObjHeader
關于SyncBlock更具體的講解還可以查看這篇文章
MethodTable的源代碼解析
MethodTable的定義(摘要)
源代碼:?https://github.com/dotnet/coreclr/blob/master/src/vm/methodtable.h
這里的字段非常多,我將會在后面的篇幅一一講解,這里先說明MethodTable中大概有什么信息
- 類型的標記,例如StaticsMask_Dynamic和StaticsMask_Generics等 (m_dwFlags) 
- 如果類型是字符串或數組還會保存每個元素的大小(ComponentSize),例如string是2 int[100]是4 
 
- 類型需要分配的內存大小 (m_BaseSize) 
- 類型信息,例如有哪些成員和是否接口等等 (m_pCanonMT) 
可以看出這個類型就是用于保存類型信息的,反射和動態Cast都需要依賴它
實際查看內存中的Object
對Object的初步分析完了,可分析對了嗎?讓我們來實際檢查一下內存中Object是什么樣子的
VisualStudio有反編譯和查看內存的功能,如下圖
這里我定義了MyClass和MyStruct類型,先看Console.WriteLine(myClass)
這里把第一個參數設置到rcx并且調用Console.WriteLine函數,為什么是rcx請看查看參考鏈接中對fastcall的介紹
rbp + 0x50 = 0x1fc8fde110
跳到內存中以后可以看到選中的這8byte是指向對象的指針,讓我們繼續跳到0x1fcad88390
這里我們可以看到MyClass實例的真面目了,選中的8byte是指向MethodTable的指針
后面分別是指向StringMember的指針和IntMember的內容
在這里指向ObjHeader的指針是一個空指針,這是正常的,微軟在代碼中有注釋This is often zero
這里是StringMember指向的內容,分別是指向MethodTable的指針,字符串長度和字符串內容
這里是MyClass的MethodTable,m_BaseSize是32
有興趣的可以去和MethodTable的成員一一對照,這里我就不跟下去了
讓我們再看下struct是怎么處理的
可以看到只是簡單的把值復制到了堆棧空間中(rbp是當前frame的堆棧基礎地址)
讓我們再來看下Console.WriteLine對于struct是怎么處理的,這里的處理相當有趣
因為需要裝箱,首先會要來一個箱子,箱子放在了rbp+30h
把MyStruct中的值復制到了箱子中,rax+8的8是把值復制到MethodTable之后
復制后,接下來把這個箱子傳給Console.WriteLine就和MyClass一樣了
另外再附一張實際查看ComponentSize的圖
彩蛋
看完了.Net中對Object的定義,讓我們再看下Python中隊Object的定義
源代碼:?https://github.com/python/cpython/blob/master/Include/object.h
定義不一樣,但是作用還是類似的
參考
http://stackoverflow.com/questions/20033353/clr-implementation-of-virtual-method-calls-via-pointer-to-base-class
http://stackoverflow.com/questions/9808982/clr-implementation-of-virtual-method-calls-to-interface-members
http://stackoverflow.com/questions/1589669/overhead-of-a-net-array
https://en.wikipedia.org/wiki/X86_calling_conventions
https://github.com/dotnet/coreclr/blob/master/src/vm/object.inl
https://github.com/dotnet/coreclr/blob/master/src/vm/object.h
https://github.com/dotnet/coreclr/blob/master/src/vm/object.cpp
https://github.com/dotnet/coreclr/blob/master/src/vm/syncblk.h
https://github.com/dotnet/coreclr/blob/master/src/vm/syncblk.cpp
https://github.com/dotnet/coreclr/blob/master/src/vm/methodtable.inl
https://github.com/dotnet/coreclr/blob/master/src/vm/methodtable.h
https://github.com/dotnet/coreclr/blob/master/src/vm/methodtable.cpp
https://github.com/dotnet/coreclr/blob/master/src/vm/class.h
https://github.com/dotnet/coreclr/blob/master/src/inc/daccess.h
https://github.com/dotnet/coreclr/blob/master/src/debug/daccess/dacfn.cpp
寫在最后
因為是剛開始閱讀coreclr的代碼,如果有誤請在留言中指出
接下來有時間我將會著重閱讀和介紹這些內容
- Object的生成和銷毀 
- Object繼承的原理(MethodTable) 
- Object同步的原理(ObjHeader, SyncBlock) 
- GC的工作方式 
- DACCESS 
原文地址:http://www.cnblogs.com/zkweb/p/6244934.html
.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注
總結
以上是生活随笔為你收集整理的CoreCLR源码探索(一) Object是什么的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: .NET Core 2.0版本预计于20
- 下一篇: 设计爬虫Hawk背后的故事
