<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      CLR探索系列:System.Object內存布局模型及實現研究

      只有深究最本質的東西,才能把握最本質的東西。

       

      有很多朋友都分析過System.Object作為Dotnet Framework里面的一個基類,她的特性、方法特點及其相關的概念,這篇博文里面,我就從System.Object這個基類的定義以及底層實現的角度,探索這個基類對象在內存里面的布局模型,探索這個基類最本質的面目。

       

       

      首先,從一個Type的實例在內存里面的布局模型、以及一個實例的各個部分在一個托管進程結構里面對應安排到相應的哪個部分說起。

         下面是一個簡單的實例結構示意圖以及邏輯結構圖:

      r_1.JPG

      2.JPG


         通常所說的對一個
      Object的引用,實際上這個ObjectRef是指向GC Heap或者是ThreadHeap里面的這個實例的Object Header這部分。而Object Header顧名思義,只是定義部分,它指向的是一個typeMethodTable。每個類型對應著一個MethodTable保存在托管堆里面。這部分的數據,它的存在是為了對一個type進行自描述。

      index指向的是一個叫做SynBlock table的表。每個Object都在這個表里面有一個record。每個record就是我們有的時候可以看到的SyncBlock。保存了相關的一些CLR對這個對象的控制的信息。

       

      我以前在研究這部分的時候,經常看到網上的一些同行們,在說明一個instance的結構的時候指出,一個object的結構,是m_SyncBlockValue后面緊接著MethodTable,然后緊接著Instance Data需要指出的是,這個理解是將一個Object的邏輯結構和在內存里面的物理結構的一些概念整到了一起,片面而不完整的。

       

      實際上,一個Object的邏輯結構,是由由兩個部分組成的。就像上面的第一個圖表示的。一個叫做ObjHeader的類,然后就是Object的具體細節實現類。Object類在實現的時候,引用了很多COM+內部對象模型的結構概念。一個ObjHeader,主要包含了兩個部分:Bit Flags以及index這兩個東西。都包含在m_SyncBlockValue相關的定義里面。

      m_SyncBlockValue是一個DWORD類型的數據,4個字節。又叫做:the index and the Bits。里面包含一個LONG的值當作index來用,還有剩下的作為某些特定功能的控制位來使用。在一個實例對象運行的時候,這些位的含義可以自動的被一些opcodes來獲取。

      m_SyncBlockValue的高六位來標記m_SyncBlockValue的各種不同的功能和用途。m_SyncBlockValue的低26位來保存hash碼,或者是SyncBlockindex或者是SpinLock。具體的后26位是標識什么東西,是由前面的6位里面的相關字段來標識出來的。

      lock一個對象時,CLR首先將m_SyncBlockValue當做一個SpinLock使用。如果CLR在有限次的重試后無法獲得SpinLock的擁有權,CLRSpinLock升級為一個AwareLockAwareLock類似與Windows中的CriticalSection

       

       

      這里需要特別說明一下為什么這么設計:

      這樣設計的好處,在于把不同功能級別的操作或者是控制代碼分離開了。數據和控制代碼分離。對于這個instance的使用者來說,instance data是最為一個實例結構的最后一部分保存在GC Heap或者是Thread Heap里面的。而對這個instance在運行的時候需要的數據或者是控制代碼,放在了MethodTable里面,從ObjHeader可以獲得到操作一個instance的時候的這些數據或者代碼。而由于程序是運行在托管的環境下面的,為了支持一些CLR的特性,我們需要給這個instance一些CLR或者說是托管環境相關的屬性。這些東西,是作為SyncBlock Table里面的一個表項保存在dotnet Framework執行引擎的內存空間里面的。這樣,就實現了不同級別的數據的隔離。

       

      我們知道,一個type的實例,也就是對象的分配,是在GC Heap上面進行分配的。一個instance和這個instance相關聯的type的相關的不同類型的數據類型,在不同的地方分配,并不是連續在一起分配的。譬如MethodTable,一些static字段,還有相關的Field或者是MethodDesc,這些東西并不是連續分配在一起的。CLR基于效率和性能上面的考慮,將它們放在了不同的地方。

      如果看過我前面對應用程序域的介紹,就會知道,對于每個托管進程,都有一個或者幾個私有的AppDomianMethodTable,就是分配在Private Appdomain的高頻堆上面(high-frequency heap),而MethodTable里面的相關的項,FieldDescsmethodDescs是分配在低頻堆里面的。而native Code,是放在JIT Heap里面的。一個Object的相關數據的分布,并不是連續的,至少有5個或者是以上的Heap來存放這些數據的分布。

      另外,SyncBlock也不是在GC Heap的,它更加特殊,是在CLR自己的私有地址空間里面的。


       

      下面,具體詳析的探索下這些結構的實現:

      首先打開ObjHeader這個類的定義:

      ************************C++ Code*****************************

      class ObjHeader

      {

        private:

          // !!! Notice: m_SyncBlockValue *MUST* be the last field in ObjHeader.

          DWORD  m_SyncBlockValue;      // the Index and the Bits

        public:

          // 訪問Sync Block表里面的相關Syncblockindex。使用位操作來獲取。

          DWORD GetHeaderSyncBlockIndex()

          {

              LEAF_CONTRACT;

       

              // pull the value out before checking it to avoid race condition

              DWORD value = m_SyncBlockValue;

                    //對于這一句含義的了解,可以通過對Bits的各個位的含義的獲取來了解。

              if ((value & (BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX |

       BIT_SBLK_IS_HASHCODE)) != BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX)

                  return 0;

              return value & MASK_SYNCBLOCKINDEX;

      }

       

             //下面的這個方法演示的是在index里面設置一個bit位的操作方法

          void SetIndex(DWORD indx)

      {

             //注意,這里定義的是一個LONG類型的變量,也就是前面說的m_SyncBlockValue里面包含一個LONG類型的index

              LONG newValue;

              LONG oldValue;

              while (TRUE) {

                           //獲取現有的LONG類型的index

                  oldValue = *(volatile LONG*)&m_SyncBlockValue;

                           //在以前的版本里面,這句是沒有的,_ASSERTE具體用途沒找到,稍后探索

                           // Access to the Sync Block Index, by masking the Value.

                  _ASSERTE(GetHeaderSyncBlockIndex() == 0);

                  // or in the old value except any index that is there -

                  // note that indx

      //could be carrying the BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX bit that we need to preserve

                  newValue = (indx |

                      (oldValue & ~(BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX |

       BIT_SBLK_IS_HASHCODE | MASK_SYNCBLOCKINDEX)));

                           //這句主要是為了保證這些位不被隨便修改掉。

                  if (FastInterlockCompareExchange((LONG*)&m_SyncBlockValue,

                                                   newValue, oldValue)== oldValue)

                  {

                      return;

                  }

              }

          }

       

          Object *GetBaseObject()

          {

              LEAF_CONTRACT;

              return (Object *) (this + 1);

      }

       

      //省略了若干對indexbit位的操作方法

      };

      ************************C++ Code end************************


         在上面的代碼中,很多關于bits flag位的定義的不了解,會對這些代碼以及內部運行機制帶來困難。下面就解釋下一個m_SyncBlockValue里面相關的BitFlags的含義:

       

             m_SyncBlockValue中,使用高位的bit來作為flags標志。在每次獲取或者是修改這些位的時候,都需要使用mask來獲取這些bits:
        

      // These first three are only used on strings (If the first one is on, we know whether

      // the string has high byte characters, and the second bit tells which way it is.

      // Note that we are reusing the FINALIZER_RUN bit since strings don't have finalizers,

      // so the value of this bit does not matter for strings

      #define BIT_SBLK_STRING_HAS_NO_HIGH_CHARS   0x80000000

       

      // Used as workaround for infinite loop case.  Will set this bit in the sblk if we have already

      // seen this sblk in our agile checking logic.  Problem is seen when object 1 has a ref to object 2

      // and object 2 has a ref to object 1.  The agile checker will infinitely loop on these references.

      #define BIT_SBLK_AGILE_IN_PROGRESS          0x80000000

      #define BIT_SBLK_STRING_HIGH_CHARS_KNOWN    0x40000000

      #define BIT_SBLK_STRING_HAS_SPECIAL_SORT    0xC0000000

      #define BIT_SBLK_STRING_HIGH_CHAR_MASK      0xC0000000

       

      #define BIT_SBLK_FINALIZER_RUN              0x40000000

      #define BIT_SBLK_GC_RESERVE                 0x20000000

       

      // This lock is only taken when we need to modify the index value in m_SyncBlockValue.

      // It should not be taken if the object already has a real syncblock index.

      #define BIT_SBLK_SPIN_LOCK                  0x10000000

       

      #define BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX    0x08000000

       

      // if BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX is clear,

      the rest of the header dword is layed out as follows:

      // - lower ten bits (bits 0 thru 9) is thread id used for the thin locks

      //   value is zero if no thread is holding the lock

      // - following six bits (bits 10 thru 15) is recursion level used for the thin locks

      //   value is zero if lock is not taken or only taken once by the same thread

      // - following 11 bits (bits 16 thru 26) is app domain index

      //   value is zero if no app domain index is set for the object

      #define SBLK_MASK_LOCK_THREADID             0x000003FF  

      #define SBLK_MASK_LOCK_RECLEVEL             0x0000FC00  

      #define SBLK_LOCK_RECLEVEL_INC              0x00000400  

      #define SBLK_APPDOMAIN_SHIFT                16          

      #define SBLK_RECLEVEL_SHIFT                 10          

      #define SBLK_MASK_APPDOMAININDEX            0x000007FF      

       

      // 如果 BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX 被設置了,并且,如果

       BIT_SBLK_IS_HASHCODE 也被設置了, 剩下的dword就是hash Code (bits 0 to 25),

      // otherwise the rest of the dword is the sync block index (bits 0 thru 25)

      #define BIT_SBLK_IS_HASHCODE            0x04000000

       

      #define MASK_HASHCODE                   ((1<<HASHCODE_BITS)-1)

      #define SYNCBLOCKINDEX_BITS             26

      #define MASK_SYNCBLOCKINDEX             ((1<<SYNCBLOCKINDEX_BITS)-1)

       

      // Spin for about 1000 cycles before waiting longer.

      #define     BIT_SBLK_SPIN_COUNT         1000

       

      // The GC is highly dependent on SIZE_OF_OBJHEADER being exactly the sizeof(ObjHeader)

      // We define this macro so that the preprocessor can calculate padding structures.

      #define SIZEOF_OBJHEADER    4


         
          可以從這些注釋里面,可以看到每個字段的大概的用法。 

      接著,就說到了index里面所指向的東西。也就是index指向的SyncBlock Table里面的記錄。首先,m_SyncBlockValue記錄的是一個instance的額外的state。如果這個值是0,就說明沒有額外的狀態。如果它有一個非零的值,CLR就會自動把這個index

      g_pSyncTable里面的SyncTableEntries這個屬性一一的對應起來。g_pSyncTable是一個全局的表,也可以說是數組,里面存儲每個變量的SyncBlock

             大多數instance的指向SyncBlockindex都是0,和其它的Object一起,共享一個虛構的SyncBlockSyncBlock的主要作用,是為了object的同步。每個對象的Hash()這個方法的實現,就是根據SyncTableEntry這個字段來實現的。同時,在一個Object(在上面的定義中,我們可以看到,一個Object在最底層的實現,是一個COM+Object)與底層的COM+交互的過程中,這里也可以存儲少量的額外的信息。

             這里,插入說一下一個SyncBlock與一個SyncTableEntry的區別。一個Objectm_SyncBlockValue里面的index指向的是g_pSyncTable這個全局表(或者數組)里面的一個記錄。這個記錄就叫做SyncBlock。而確定index和表里面的哪一個SyncBlock的對應關系的就是每個SyncBlock里面的SyncTableEntry的這個字段。

             同時,SyncTableEntrySyncBlock都是分配非GC回收內存里面的,因為g_pSyncTable就是分配在非GC堆上面,也就是CLR的私有內存里面的。然后,有一個弱類型的pointer指向每個instanceSyncTableEntry這個字段,用于這些對象的回收。

       

      SyncTableEntries在以前版本的framework里面還是以一個結構體的形式出現的,到了后來的版本,就2.0后來的版本,就改寫成了一個class

       

             class SyncTableEntry

      {

        public:

          PTR_SyncBlock    m_SyncBlock;

          Object   *m_Object;

          static SyncTableEntry*& GetSyncTableEntry();

      };

       

      從上面可以看到,每個SyncTableEntry都包含了一個向前和向后的指針。向后退回到Object,向前指向SyncTableEntry對應的SyncBlock

      GetSyncTableEntry()方法中,直接返回了g_pSyncTable

       

      SyncTableEntry*& SyncTableEntry::GetSyncTableEntry()

      {

          LEAF_CONTRACT;

          return g_pSyncTable;

      }    

       

      對于g_pSyncTable,實際上是一個叫做SyncBlockArray的數組。其定義如下

       

      class  SyncBlockArray

      {

        public:

          SyncBlockArray *m_Next;

          BYTE            m_Blocks[MAXSYNCBLOCK * sizeof (SyncBlock)];

      };

       

      在上面的定義的過程中,使用m_Blocks[MAXSYNCBLOCK * sizeof (SyncBlock)]這句,可以保證在大多數只指定了SyncTableEntry而沒有指定值的情況下的性能。

       

      OK,截止到這里,對System.Object這個最基本的類,是如何來實現的,及其在內存里面的布局,和針對這個布局程序上是如何實現的,有了一個較為深入的探索。

      了解了這些東西,對于探索一個托管引用程序在運行時的特性,以及探索一個托管經常的運行時的內部機制的各個細節問題,都有了一個開山鋪路的先驅。

       

      在接下來的2008,將繼續深入研究Dotnet最底層的核心運行機制,把這些鮮為人知的“那些事”,都展示出來,拋磚引玉,彌補一下國內大多數人只注重一些編程技巧和控件使用現狀的不足吧。

       

      后記:

      在后來的修改過程中,更正了幾個表達不準確的地方,同時加了兩個簡單的圖,希望有駐與文章的閱讀吧。
         另外,剛剛百度了一下“g_pSyncTable”,只有一條記錄,Google了一下,也剛剛一頁,都還是koders上面的。不過找到了一個不錯介紹這方面的PPTPDF

      http://tmd.havit.cz/Teaching/CSharp/Lecture5/ObjectInternals.pdf

      希望對對這方面有興趣的朋友有用。

      下次研究這方面的朋友們bandu這些關鍵字,就可以多一條記錄了。^_^我也算一個先驅者吧。

       

      謹以此文攢人品。

       

      updated at 2008年1月20日17:41:54 

       

      posted on 2008-01-18 21:47  lbq1221119  閱讀(5615)  評論(22)    收藏  舉報

      導航

      主站蜘蛛池模板: 日本一区二区在线高清观看| 久久精品国产99精品亚洲| 国产99精品成人午夜在线| 91精品乱码一区二区三区 | 福利视频在线一区二区| 麻豆一区二区三区香蕉视频| 九九热爱视频精品视频| 人妻伦理在线一二三区| 亚洲αⅴ无码乱码在线观看性色 | 日本一区三区高清视频| 久久大香萑太香蕉av黄软件| 天天综合亚洲色在线精品| 四虎永久精品在线视频| 91国产自拍一区二区三区| 加勒比无码人妻东京热| 香蕉影院在线观看| 人妻熟女一二三区夜夜爱| 国产成人亚洲综合图区| 平山县| 国产精品白丝一区二区三区| 精品999日本久久久影院| 亚洲午夜无码久久久久蜜臀av| 美腿丝袜亚洲综合第一页| 伊人春色激情综合激情网| 素人视频亚洲十一十二区| 色爱无码av综合区| 亚洲国产成人久久综合一区77 | 亚洲第一区二区国产精品| 国产不卡精品一区二区三区| 麻豆精品在线| 99麻豆久久精品一区二区| 粗壮挺进邻居人妻无码| 亚洲精品无码成人A片九色播放| 一区二区三区无码免费看| 亚洲欧美综合在线天堂| 亚洲成人av在线高清| 亚洲精品无码高潮喷水A| 九九久久精品国产免费看小说| 国产网友愉拍精品视频手机| 国产av亚洲精品ai换脸电影| 干中文字幕|