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

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

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

      [你必須知道的.NET]第十九回:對象創(chuàng)建始末(下)

      博客園CLR基礎(chǔ)研究團(tuán)隊(duì)|CLR團(tuán)隊(duì)精品系列|Anytao技術(shù)博客

       

      [你必須知道的.NET]第十九回:對象創(chuàng)建始末(下)

      發(fā)布日期:2007.12.7 作者:Anytao
      ? 2007 Anytao.com ,原創(chuàng)作品,轉(zhuǎn)貼請注明作者和出處。

       

      本文將介紹以下內(nèi)容:

      • 對象的創(chuàng)建過程
      • 內(nèi)存分配分析
      • 內(nèi)存布局研究

      接上回[第十八回:對象創(chuàng)建始末(上)],繼續(xù)對對象創(chuàng)建話題的討論>>>

      2.2 托管堆的內(nèi)存分配機(jī)制

      引用類型的實(shí)例分配于托管堆上,而線程棧卻是對象生命周期開始的地方。對32位處理器來說,應(yīng)用程序完成進(jìn)程初始化后,CLR將在進(jìn)程的可用地址空間上分配一塊保留的地址空間,它是進(jìn)程(每個(gè)進(jìn)程可使用4GB)中可用地址空間上的一塊內(nèi)存區(qū)域,但并不對應(yīng)于任何物理內(nèi)存,這塊地址空間即是托管堆。

      托管堆又根據(jù)存儲信息的不同劃分為多個(gè)區(qū)域,其中最重要的是垃圾回收堆(GC Heap)和加載堆(Loader Heap),GC Heap用于存儲對象實(shí)例,受GC管理;Loader Heap又分為High-Frequency HeapLow-Frequency HeapStub Heap,不同的堆上又存儲不同的信息。Loader Heap最重要的信息就是元數(shù)據(jù)相關(guān)的信息,也就是Type對象,每個(gè)TypeLoader Heap上體現(xiàn)為一個(gè)Method Table(方法表),而Method Table中則記錄了存儲的元數(shù)據(jù)信息,例如基類型、靜態(tài)字段、實(shí)現(xiàn)的接口、所有的方法等等。Loader Heap不受GC控制,其生命周期為從創(chuàng)建到AppDomain卸載。

      在進(jìn)入實(shí)際的內(nèi)存分配分析之前,有必要對幾個(gè)基本概念做以交代,以便更好的在接下來的分析中展開討論。

      ·       TypeHandle,類型句柄,指向?qū)?yīng)實(shí)例的方法表,每個(gè)對象創(chuàng)建時(shí)都包含該附加成員,并且占用4個(gè)字節(jié)的內(nèi)存空間。我們知道,每個(gè)類型都對應(yīng)于一個(gè)方法表,方法表創(chuàng)建于編譯時(shí),主要包含了類型的特征信息、實(shí)現(xiàn)的接口數(shù)目、方法表的slot數(shù)目等。

      ·       SyncBlockIndex,用于線程同步,每個(gè)對象創(chuàng)建時(shí)也包含該附加成員,它指向一塊被稱為Synchronization Block的內(nèi)存塊,用于管理對象同步,同樣占用4個(gè)字節(jié)的內(nèi)存空間。

      ·       NextObjPtr,由托管堆維護(hù)的一個(gè)指針,用于標(biāo)識下一個(gè)新建對象分配時(shí)在托管堆中所處的位置。CLR初始化時(shí),NextObjPtr位于托管堆的基地址。

      因此,我們對引用類型分配過程應(yīng)該有個(gè)基本的了解,由于本篇示例中FileStream類型的繼承關(guān)系相對復(fù)雜,在此本文實(shí)現(xiàn)一個(gè)相對簡單的類型來做說明:

      //@ 2007 Anytao.com 
      //http://www.anytao.com
          public class UserInfo
          {
              
      private Int32 age = -1;
              
      private char level = 'A';
          }

          
      public class User
          {
              
      private Int32 id;
              
      private UserInfo user;
          }

          
      public class VIPUser : User
          {
              
      public bool isVip;

              
      public bool IsVipUser()
              {
                  
      return isVip;
              }

              
      public static void Main()
              {
                  VIPUser aUser;
                  aUser 
      = new VIPUser();
                  aUser.isVip 
      = true;
                  Console.WriteLine(aUser.IsVipUser());
              }
          }

      將上述實(shí)例的執(zhí)行過程,反編譯為IL語言可知:new關(guān)鍵字被編譯為newobj指令來完成對象創(chuàng)建工作,進(jìn)而調(diào)用類型的構(gòu)造器來完成其初始化操作,在此我們詳細(xì)的描述其執(zhí)行的具體過程:

      ·       首先,將聲明一個(gè)引用類型變量aUser

                  VIPUser aUser;

      它僅是一個(gè)引用(指針),保存在線程的堆棧上,占用4Byte的內(nèi)存空間,將用于保存VIPUser對象的有效地址,其執(zhí)行過程正是上文描述的在線程棧上的分配過程。此時(shí)aUser未指向任何有效的實(shí)例,因此被自行初始化為null,試圖對aUser的任何操作將拋出NullReferenceException異常。

      ·       接著,通過new操作執(zhí)行對象創(chuàng)建:

                  aUser = new VIPUser();

      如上文所言,該操作對應(yīng)于執(zhí)行newobj指令,其執(zhí)行過程又可細(xì)分為以下幾步:

      aCLR按照其繼承層次進(jìn)行搜索,計(jì)算類型及其所有父類的字段,該搜索將一直遞歸到System.Object類型,并返回字節(jié)總數(shù),以本例而言類型VIPUser需要的字節(jié)總數(shù)為15Byte,具體計(jì)算為:VIPUser類型本身字段isVip(bool型)為1Byte;父類User類型的字段id(Int32型)為4Byte,字段user保存了指向UserInfo型的引用,因此占4Byte,而同時(shí)還要為UserInfo分配6Byte字節(jié)的內(nèi)存。

      實(shí)例對象所占的字節(jié)總數(shù)還要加上對象附加成員所需的字節(jié)總數(shù),其中附加成員包括TypeHandle和SyncBlockIndex,共計(jì)8字節(jié)(在32位CPU平臺下)。因此,需要在托管堆上分配的字節(jié)總數(shù)為23字節(jié),而堆上的內(nèi)存塊總是按照4Byte的倍數(shù)進(jìn)行分配,因此本例中將分配24字節(jié)的地址空間。

      cCLR在當(dāng)前AppDomain對應(yīng)的托管堆上搜索,找到一個(gè)未使用的20字節(jié)的連續(xù)空間,并為其分配該內(nèi)存地址。事實(shí)上,GC使用了非常高效的算法來滿足該請求,NextObjPtr指針只需要向前推進(jìn)20個(gè)字節(jié),并清零原NextObjPtr指針和當(dāng)前NextObjPtr指針之間的字節(jié),然后返回原NextObjPtr指針地址即可,該地址正是新創(chuàng)建對象的托管堆地址,也就是aUser引用指向的實(shí)例地址。而此時(shí)的NextObjPtr仍指向下一個(gè)新建對象的位置。注意,棧的分配是向低地址擴(kuò)展,而堆的分配是向高地址擴(kuò)展。

      另外,實(shí)例字段的存儲是有順序的,由上到下依次排列,父類在前子類在后,詳細(xì)的分析請參見[第十五回:繼承本質(zhì)論]

      在上述操作時(shí),如果試圖分配所需空間而發(fā)現(xiàn)內(nèi)存不足時(shí),GC將啟動垃圾收集操作來回收垃圾對象所占的內(nèi)存,我們將以后對此做詳細(xì)的分析。

      ·       最后,調(diào)用對象構(gòu)造器,進(jìn)行對象初始化操作,完成創(chuàng)建過程。該構(gòu)造過程,又可細(xì)分為以下幾個(gè)環(huán)節(jié):

         a)構(gòu)造VIPUser類型的Type對象,主要包括靜態(tài)字段、方法表、實(shí)現(xiàn)的接口等,并將其分配在上文提到托管堆的Loader Heap上。

      b)初始化aUser的兩個(gè)附加成員:TypeHandleSyncBlockIndex。將TypeHandle指針指向Loader Heap上的MethodTableCLR將根據(jù)TypeHandle來定位具體的Type;將SyncBlockIndex指針指向Synchronization Block的內(nèi)存塊,用于在多線程環(huán)境下對實(shí)例對象的同步操作。

      c)調(diào)用VIPUser的構(gòu)造器,進(jìn)行實(shí)例字段的初始化。實(shí)例初始化時(shí),會首先向上遞歸執(zhí)行父類初始化,直到完成System.Object類型的初始化,然后再返回執(zhí)行子類的初始化,直到執(zhí)行VIPUser類為止。以本例而言,初始化過程為首先執(zhí)行System.Object類,再執(zhí)行User類,最后才是VIPUser類。最終,newobj分配的托管堆的內(nèi)存地址,被傳遞給VIPUserthis參數(shù),并將其引用傳給棧上聲明的aUser

      上述過程,基本完成了一個(gè)引用類型創(chuàng)建、內(nèi)存分配和初始化的整個(gè)流程,然而該過程只能看作是一個(gè)簡化的描述,實(shí)際的執(zhí)行過程更加復(fù)雜,涉及到一系列細(xì)化的過程和操作。對象創(chuàng)建并初始化之后,內(nèi)存的布局,可以表示為:

          由上文的分析可知,在托管堆中增加新的實(shí)例對象,只是將
      NextObjPtr指針增加一定的數(shù)值,再次新增的對象將分配在當(dāng)前NextObjPtr指向的內(nèi)存空間,因此在托管堆棧中,連續(xù)分配的對象在內(nèi)存中一定是連續(xù)的,這種分配機(jī)制非常高效。

      2.3 必要的補(bǔ)充

      有了對象創(chuàng)建的基本流程概念,下面的幾個(gè)問題時(shí)常引起大家的思考,在此本文一并做以探索:

      ·       值類型中的引用類型字段和引用類型中的值類型字段,其分配情況又是如何?

          這一思考其實(shí)是一個(gè)問題的兩個(gè)方面:對于值類型嵌套引用類型的情況,引用類型變量作為值類型的成員變量,在堆棧上保存該成員的引用,而實(shí)際的引用類型仍然保存在GC堆上;對于引用類型嵌套值類型的情況,則該值類型字段將作為引用類型實(shí)例的一部分保存在GC堆上。在[ 第八回:品味類型---值類型與引用類型(上)-內(nèi)存有理]一文對這種嵌套結(jié)構(gòu),有較詳細(xì)的分析。對于值類型,你只要記著它總是分配在聲明它的地方。

      ·       方法保存在Loader HeapMethodTable中,那么方法調(diào)用時(shí)又是怎么樣的過程?

      如上文所言,MethodTable中包含了類型的元數(shù)據(jù)信息,類在加載時(shí)會在Loader Heap上創(chuàng)建這些信息,一個(gè)類型在內(nèi)存中對應(yīng)一份MethodTable,其中包含了所有的方法、靜態(tài)字段和實(shí)現(xiàn)的接口信息等。對象實(shí)例的TypeHandle在實(shí)例創(chuàng)建時(shí),將指向MethodTable開始位置的偏移處(默認(rèn)偏移12Byte),通過對象實(shí)例調(diào)用某個(gè)方法時(shí),CLR根據(jù)TypeHandle可以找到對應(yīng)的MethodTable,進(jìn)而可以定位到具體的方法,再通過JIT CompilerIL指令編譯為本地CPU指令,該指令將保存在一個(gè)動態(tài)內(nèi)存中,然后在該內(nèi)存地址上執(zhí)行該方法,同時(shí)該CPU指令被保存起來用于下一次的執(zhí)行。

      MethodTable中,包含一個(gè)Method Slot Table,稱為方法槽表,該表是一個(gè)基于方法實(shí)現(xiàn)的線性鏈表,并按照以下順序排列:繼承的虛方法,引入的虛方法,實(shí)例方法和靜態(tài)方法。方法表在創(chuàng)建時(shí),將按照繼承層次向上搜索父類,直到System.Object類型,如果子類覆寫了父類方法,則將會以子類方法覆蓋父類虛方法。關(guān)于方法表的創(chuàng)建過程,可以參考[第十五回:繼承本質(zhì)論]中的描述。

      ·       靜態(tài)字段的內(nèi)存分配和釋放,又有何不同?

          靜態(tài)字段也保存在方法表中,位于方法表的槽數(shù)組后,其生命周期為從創(chuàng)建到AppDomain卸載。因此一個(gè)類型無論創(chuàng)建多少個(gè)對象,其靜態(tài)字段在內(nèi)存中也只有一份。靜態(tài)字段只能由靜態(tài)構(gòu)造函數(shù)進(jìn)行初始化,靜態(tài)構(gòu)造函數(shù)確保在類型任何對象創(chuàng)建前,或者在任何靜態(tài)字段或方法被引用前執(zhí)行,其詳細(xì)的執(zhí)行順序請參考相關(guān)討論。

      3. 結(jié)論

      對象創(chuàng)建過程的了解,是從底層接觸CLR運(yùn)行機(jī)制的入口,也是認(rèn)識.NET自動內(nèi)存管理的關(guān)鍵。通過本文的詳細(xì)論述,關(guān)于對象的創(chuàng)建、內(nèi)存分配、初始化過程和方法調(diào)用等技術(shù)都會建立一個(gè)相對全面的理解,同時(shí)也清楚的把握了線程棧和托管堆的執(zhí)行機(jī)制。

      對象總是有生有滅,本文簡述其生,這是個(gè)偉大的開始。 

      [祝福] 一個(gè)值得紀(jì)念的日子,一切快樂、平安、健康,這次專注,2008會更好。

      參考文獻(xiàn)

      (USA)Joe Duffy, Professinal .NET Framework 2.0
      (USA)Don Box, Essiential .NET
      (MSDN)Hanu Kommalapati and Tom Christian, Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects, http://msdn.microsoft.com/msdnmag/issues/05/05/JITCompiler/default.aspx

      溫故知新

      [開篇有益]
      [第一回:恩怨情仇:is和as]
      [第二回:對抽象編程:接口和抽象類]
      [第三回:歷史糾葛:特性和屬性]
      [第四回:后來居上:class和struct]
      [第五回:深入淺出關(guān)鍵字---把new說透]
      [第六回:深入淺出關(guān)鍵字---base和this]
      [第七回:品味類型---從通用類型系統(tǒng)開始]
      [第八回:品味類型---值類型與引用類型(上)-內(nèi)存有理]
      [第九回:品味類型---值類型與引用類型(中)-規(guī)則無邊]
      [第十回:品味類型---值類型與引用類型(下)-應(yīng)用征途]
      [第十一回:參數(shù)之惑---傳遞的藝術(shù)(上)]
      [第十二回:參數(shù)之惑---傳遞的藝術(shù)(下)]
      [第十三回:從Hello, world開始認(rèn)識IL]
      [第十四回:認(rèn)識IL代碼---從開始到現(xiàn)在]
      [第十五回:繼承本質(zhì)論]
      [第十六回:深入淺出關(guān)鍵字---using全接觸]
      [第十七回:貌合神離:覆寫和重載]
      [第十八回:對象創(chuàng)建始末(上)]

      ? 2007 Anytao.com

      原創(chuàng)作品,轉(zhuǎn)貼請注明作者和出處,留此信息。

      本文以“現(xiàn)狀”提供且沒有任何擔(dān)保,同時(shí)也沒有授予任何權(quán)利。
      This posting is provided "AS IS" with no warranties, and confers no rights.

      posted @ 2007-12-07 08:55  Anytao  閱讀(11480)  評論(46)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产麻豆9l精品三级站| 美女又黄又免费的视频| 欧美午夜成人片在线观看| 国产成人8X人网站视频| 国产乱码精品一区二区麻豆 | 91精品乱码一区二区三区| 国产AV影片麻豆精品传媒| 国产乱老熟女乱老熟女视频| 国产男女猛烈无遮挡免费视频网址| 少妇粗大进出白浆嘿嘿视频| 2018年亚洲欧美在线v| 国产SM重味一区二区三区| 色狠狠色婷婷丁香五月| 丁香婷婷在线观看| 精品一区二区不卡无码AV| 国产偷窥熟女高潮精品视频| 国产精品午夜福利精品| 国产精品国产高清国产av| 国产69精品久久久久99尤物| 99国产午夜福利在线观看| 国产亚洲精品成人aa片新蒲金| 国产91丝袜在线播放动漫| 五月丁香六月综合缴情在线| 大又大又粗又硬又爽少妇毛片| 国产一区二区精品偷系列| 久久精品国产九一九九九| caoporn免费视频公开| 人妻在线无码一区二区三区| 国产精品一区二区三区日韩| 久爱无码精品免费视频在线观看| 色婷婷日日躁夜夜躁| 热久久美女精品天天吊色| 久久精品伊人狠狠大香网| 亚洲国产美女精品久久久| 亚洲中文久久久精品无码| 日本不卡不二三区在线看| 加勒比中文字幕无码一区| 亚洲精品国产美女久久久| 亚洲人成电影在线天堂色| 亚洲av影院一区二区三区| 国产自拍一区二区三区在线|