1. 程式人生 > 其它 >萬物之源,Object到底是個什麼東西?

萬物之源,Object到底是個什麼東西?

技術標籤:

CLR裡面規定了,Object是所有類的父類或者基類,有點意思的是貌似是所有的類的祖先都是它,沒有它就沒有後代子孫繁衍。(如果你有任何問題,可以加入QQ群676817308大家一起討論交流)

其實它到底是啥呢?

光看namespace為system的名稱空間下的Object類,裡面什麼都沒有

namespace System
{
	/// <summary>Supports all classes in the .NET Framework class hierarchy and provides low-level services to derived classes. This is the ultimate base class of all classes in the .NET Framework; it is the root of the type hierarchy.</summary>
public class Object { //這裡省略了一些方法 } }

這就有點意思了,那其實真正的儲存資料的地方在哪裡呢?繼續看CLR

標頭檔案 syncblk.h裡面,包含了object頭

class ObjHeader
{
    friend class CheckAsmOffsets;

  private:
    // !!! Notice: m_SyncBlockValue *MUST* be the last field in ObjHeader.
#ifdef _WIN64
    DWORD    m_alignpad;
#endif // _WIN64

    Volatile<
DWORD> m_SyncBlockValue; // the Index and the Bits }

這個裡面就包含了兩個欄位

標頭檔案object.h裡面發現了object C++類

class Object
{
  protected:
    PTR_MethodTable m_pMethTab;

 PTR_ObjHeader   GetHeader()
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return dac_cast<PTR_ObjHeader>(this) - 1;
    }
    
  PTR_BYTE   GetData
(void) { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; return dac_cast<PTR_BYTE>(this) + sizeof(Object); } }

這個類裡面就包含了一個指標類m_pMethTab
裡面有個方法GetHeader,獲取頭部指標,這個頭部有點意思,在當前methodtable的位置減去一個header(頭部)長度的距離,就是存放header指標的起始地址。
裡面有個方法GetData,獲取欄位資料。這個欄位資料的位置,在當前類的指標位置+object類的長度,實際上就是在object類的結尾處,包含了欄位資料。

捋一下,實際上就是 頭部(header)------(方法表))methodtable-------(欄位)data構成了 .Net 裡面的所謂的Object,所有類的始祖。

實際來看個例子

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            A a = new A();
            a.aa();
        }
    }
    public class A
    {
        int i = 0; 
        int k = 0;
        public string aa()
        {
             string j = "A Class";
            return j;
        }
    }
}

這是個簡單的C#控制檯
我們在return j打斷點,把 class A 進行一個反編譯

    20:              string j = "A Class";
00007FFD7DFB2AD0 48 B8 A8 30 FB A2 65 01 00 00 mov         rax,165A2FB30A8h  
00007FFD7DFB2ADA 48 8B 00             mov         rax,qword ptr [rax]  
00007FFD7DFB2ADD 48 89 45 30          mov         qword ptr [rbp+30h],rax  
    21:             return j
;```


可以看到 j的儲存位置為 rbp+30h。我們來看看暫存器當前rbp的值,RBP = 0000002AD1D7E2F0。
那麼j地址應該為,2AD1D7E320,在這個位置上我們繼續看。

```bash
0x0000002AD1D7E320
0000016592fd3258 0000000000000000 0000016592fd1470 0000002ad1d7e390 0000002ad1d7e350

因為class 是引用型別,這個rbp+30h儲存的地方只是個地址值,也就是引用型別的指標。我們繼續深入,把記憶體跳轉到0000016592fd3258

0x0000016592FD3258
20 0b 3d b4 fd 7f 00 00 07 00 00 00 41 00 20 00 43 00 6c 00 61 00 73 00 73 00 00 00 00 00 00 00 00

注意到這個地方,前面八個位元組是物件頭,也就是objectheader。接著後面四個位元組是00000007,表示j變數有包含了七個字元,七個字元分別表示什麼呢?我們繼續接著看。十六進位制的0041的ASCII碼是A,十六進位制的0020 ASCII碼是個空格,再往後,0043的ASCII的碼是C。其實組合起來就是A空格C,其實也就是上面j變數的值,A Class的值。後面以此類推,不多說。

整個的一個Object大約就是這麼樣一個東西。