一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

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

系列文章導航:

[你必須知道的.NET] 開篇有益

[你必須知道的.NET] 第一回:恩怨情仇:is和as

[你必須知道的.NET] 第二回:對抽象編程:接口和抽象類

[你必須知道的.NET] 第三回:歷史糾葛:特性和屬性

[你必須知道的.NET] 第四回:后來居上:class和struct

[你必須知道的.NET] 第五回:深入淺出關鍵字---把new說透

[你必須知道的.NET] 第六回:深入淺出關鍵字---base和this

[你必須知道的.NET] 第七回:品味類型---從通用類型系統開始

[你必須知道的.NET] 第八回:品味類型---值類型與引用類型(上)-內存有理

[你必須知道的.NET] 第九回:品味類型---值類型與引用類型(中)-規則無邊

[你必須知道的.NET] 第十回:品味類型---值類型與引用類型(下)-應用征途

[你必須知道的.NET] 第十一回:參數之惑---傳遞的藝術(上)

[你必須知道的.NET] 第十二回:參數之惑---傳遞的藝術(下)

[你必須知道的.NET] 第十三回:從Hello, world開始認識IL

[你必須知道的.NET] 第十四回:認識IL代碼---從開始到現在

[你必須知道的.NET] 第十五回:繼承本質論

[你必須知道的.NET] 第十六回:深入淺出關鍵字---using全接觸

[你必須知道的.NET] 第十七回:貌合神離:覆寫和重載

[你必須知道的.NET] 第十八回:對象創建始末(上)

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

[你必須知道的.NET]第二十回:學習方法論

[你必須知道的.NET]第二十一回:認識全面的null

[你必須知道的.NET]第二十二回:字符串駐留(上)---帶著問題思考

[你必須知道的.NET]第三十二回,深入.NET 4.0之,Tuple一二


  本文將介紹以下內容:

  • 對象的創建過程

  • 內存分配分析

  • 內存布局研究

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

  2.2 托管堆的內存分配機制

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

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

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

  • TypeHandle,類型句柄,指向對應實例的方法表,每個對象創建時都包含該附加成員,并且占用4個字節的內存空間。我們知道,每個類型都對應于一個方法表,方法表創建于編譯時,主要包含了類型的特征信息、實現的接口數目、方法表的slot數目等。

  • SyncBlockIndex,用于線程同步,每個對象創建時也包含該附加成員,它指向一塊被稱為Synchronization Block的內存塊,用于管理對象同步,同樣占用4個字節的內存空間。

  • NextObjPtr,由托管堆維護的一個指針,用于標識下一個新建對象分配時在托管堆中所處的位置。CLR初始化時,NextObjPtr位于托管堆的基地址。

  因此,我們對引用類型分配過程應該有個基本的了解,由于本篇示例中FileStream類型的繼承關系相對復雜,在此本文實現一個相對簡單的類型來做說明:

Code

系列文章導航:

[你必須知道的.NET] 開篇有益

[你必須知道的.NET] 第一回:恩怨情仇:is和as

[你必須知道的.NET] 第二回:對抽象編程:接口和抽象類

[你必須知道的.NET] 第三回:歷史糾葛:特性和屬性

[你必須知道的.NET] 第四回:后來居上:class和struct

[你必須知道的.NET] 第五回:深入淺出關鍵字---把new說透

[你必須知道的.NET] 第六回:深入淺出關鍵字---base和this

[你必須知道的.NET] 第七回:品味類型---從通用類型系統開始

[你必須知道的.NET] 第八回:品味類型---值類型與引用類型(上)-內存有理

[你必須知道的.NET] 第九回:品味類型---值類型與引用類型(中)-規則無邊

[你必須知道的.NET] 第十回:品味類型---值類型與引用類型(下)-應用征途

[你必須知道的.NET] 第十一回:參數之惑---傳遞的藝術(上)

[你必須知道的.NET] 第十二回:參數之惑---傳遞的藝術(下)

[你必須知道的.NET] 第十三回:從Hello, world開始認識IL

[你必須知道的.NET] 第十四回:認識IL代碼---從開始到現在

[你必須知道的.NET] 第十五回:繼承本質論

[你必須知道的.NET] 第十六回:深入淺出關鍵字---using全接觸

[你必須知道的.NET] 第十七回:貌合神離:覆寫和重載

[你必須知道的.NET] 第十八回:對象創建始末(上)

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

[你必須知道的.NET]第二十回:學習方法論

[你必須知道的.NET]第二十一回:認識全面的null

[你必須知道的.NET]第二十二回:字符串駐留(上)---帶著問題思考

[你必須知道的.NET]第三十二回,深入.NET 4.0之,Tuple一二


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

 

  在上述操作時,如果試圖分配所需空間而發現內存不足時,GC將啟動垃圾收集操作來回收垃圾對象所占的內存,我們將以后對此做詳細的分析。

  • 最后,調用對象構造器,進行對象初始化操作,完成創建過程。該構造過程,又可細分為以下幾個環節:

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

  (b)初始化aUser的兩個附加成員:TypeHandle和SyncBlockIndex。將TypeHandle指針指向Loader Heap上的MethodTable,CLR將根據TypeHandle來定位具體的Type;將SyncBlockIndex指針指向Synchronization Block的內存塊,用于在多線程環境下對實例對象的同步操作。

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

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

  由上文的分析可知,在托管堆中增加新的實例對象,只是將NextObjPtr指針增加一定的數值,再次新增的對象將分配在當前NextObjPtr指向的內存空間,因此在托管堆棧中,連續分配的對象在內存中一定是連續的,這種分配機制非常高效。

  2.3 必要的補充

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

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

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

  • 方法保存在Loader Heap的MethodTable中,那么方法調用時又是怎么樣的過程?

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

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

  • 靜態字段的內存分配和釋放,又有何不同?

  靜態字段也保存在方法表中,位于方法表的槽數組后,其生命周期為從創建到AppDomain卸載。因此一個類型無論創建多少個對象,其靜態字段在內存中也只有一份。靜態字段只能由靜態構造函數進行初始化,靜態構造函數確保在類型任何對象創建前,或者在任何靜態字段或方法被引用前執行,其詳細的執行順序請參考相關討論。

  3. 結論

  對象創建過程的了解,是從底層接觸CLR運行機制的入口,也是認識.NET自動內存管理的關鍵。通過本文的詳細論述,關于對象的創建、內存分配、初始化過程和方法調用等技術都會建立一個相對全面的理解,同時也清楚的把握了線程棧和托管堆的執行機制。

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

                              © 2007 Anytao.com

NET技術[你必須知道的.NET] 第十九回:對象創建始末(下),轉載需保留來源!

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

主站蜘蛛池模板: 国内精品久久影院 | 日韩美女一区二区三区 | 99在线观看视频免费精品9 | 欧美女人性视频 | 天干天干夜天干天天爽 | 玖玖精品在线视频 | 色老板成人永久免费视频 | 亚洲小说图片 | 亚洲大成色www永久网 | 亚洲欧美色鬼久久综合 | 久久精品中文字幕久久 | 久久精品免费一区二区三区 | 精品一二三区 | 亚洲一区免费在线 | 国产精品 第二页 | 最新国产在线观看福利91 | 天天综合日日噜噜噜 | 国产成人最新毛片基地 | 思思玖玖 | 欧美激情片在线观看 | 最新欧美精品一区二区三区不卡 | 一区二区三区在线观看视频 | 丁香婷婷色 | 91短视频网址 | 国产aⅴ精品一区二区三区久久 | 亚1洲二区三区四区免费 | 91在线精品老司机免费播放 | 劲爆欧美第一页 | 激情有码 | 亚洲成人中文字幕 | 国产精品自在线拍国产 | 国产精品久热 | 美女大胸又爽又黄网站 | 久久精品国产99久久72 | se成人国产精品 | 国产成人午夜视频 | 九九全国免费视频 | 春暖花开亚洲x8永久地址 | 欧美在线视频网站 | 偷拍亚洲色图 | 九色国产在视频线精品视频 |