new,is和as运算符解析及运行时类型,对象,线程堆栈,托管堆之间的联系
CLR要求對象必須使用new運算符創(chuàng)建,在使用new運算符創(chuàng)建一個對象時具體都做了些什么呢?
1.計算所有定義的實例字段,所有的基類型包括System.Object需要分配的字節(jié)數(shù)。
每一個堆上的對象還需要兩個額外的成員:類型對象指針 和同步塊索引,CLR使用它們來管理對象。它們兩個需要的字節(jié)數(shù)算在對象的大小里面。
2.從托管堆分配對象需要的字節(jié)數(shù)(也就是給對象分配內(nèi)存)。所有的字節(jié)置為0
3.初始化類型對象指針 和同步塊索引
4.調(diào)用實例構(gòu)造器。大多數(shù)編譯器自動生成調(diào)用基類構(gòu)造器的代碼。最終會調(diào)用Sytem.Object的構(gòu)造器,這個構(gòu)造器方法什么也不做,只是return。
在new執(zhí)行完上面的操作以后,返回一個新創(chuàng)建的對象的引用,這個引用保存在實例對象變量里。如:A a=new A();?? 保存在變量a里。
?
is和as運算符
//o是一個Object對象 Employee是一個類 if(o is Employee) {Employee e=(Employee)o;... }上面的代碼是關(guān)于is非常典型的應(yīng)用,這里CLR會進(jìn)行兩次類型 檢查:①is運算符檢查 ? ②執(zhí)行強轉(zhuǎn)的時候檢查。CLR的類型檢查提高了安全性,同時也會消耗一部分性能。C#提供了as運算符來簡化代碼并且改善性能。
Employee e=o as Employee; if(e!=null) {//... }這里CLR會檢查o的類型是否兼容Employee,如果兼容則返回Employee對象的引用,否則返回null。這里只執(zhí)行了一次類型檢查。
?
運行時類型,對象,線程堆棧,托管堆之間的聯(lián)系
當(dāng)創(chuàng)建一個線程時,會分配1M的堆棧空間,用來向方法傳遞參數(shù)以及存放定義在方法里面的局部變量。堆棧的建造是從高位內(nèi)存地址向地位內(nèi)存地址進(jìn)行。下面演示一個線程執(zhí)行調(diào)用M1方法的過程:
M1方法執(zhí)行時,首先會在堆棧上為name變量分配內(nèi)存:
接著M1調(diào)用M2方法,將name局部變量作為參數(shù)參數(shù)傳遞,name變量的地址進(jìn)棧:
接著會執(zhí)行M2方法,首先還是給length和tally兩個局部變量從堆棧上分配內(nèi)存:
M2執(zhí)行到return語句,返回到M1,繼續(xù)執(zhí)行。
?
調(diào)用靜態(tài)方法,實例方法以及虛方法之間的不同
internal class Employee { public Int32 GetYearsEmployed() { ... } public virtual String GetProgressReport() { ... } public static Employee Lookup(String name) { ... } } internal sealed class Manager : Employee { public override String GetProgressReport() { ... } }加入代碼接著調(diào)用M3方法,M3方法包含的代碼闡釋了CLR的運行原理(一般可能不這樣寫代碼)
上圖展示CLR載入到進(jìn)程,托管堆初始化。
當(dāng)JIT編譯器將M3的IL代碼編譯為本地CPU指令時,CLR會保證定義這些類型的程序集加載。使用程序集的元數(shù)據(jù),CLR這些類型的信息并創(chuàng)建一些數(shù)據(jù)結(jié)構(gòu)來呈現(xiàn)類型本身。關(guān)于Employee和Manager類型展示如下:
(Int32和String是常用的類型,這里沒有展示)
1.在定義一個類型時,可以定義一個靜態(tài)數(shù)據(jù)字段,存放類型對象本身的內(nèi)存分配的字節(jié)數(shù)。每一個類型對象里面是一個包含每個方法入口的方法表,這里的Employee定義了GetYearsEmployed , GetProgressReport, 和Lookup三個方法,所以在Employee的方法表里面有三個入口。在CLR確定了所有的方法被創(chuàng)建并編譯之后,線程開始執(zhí)行M3的CPU指令。同樣,這里會為M3方法的局部變量分配內(nèi)存,(初值為0或null)。
2.接著M3執(zhí)行構(gòu)造器創(chuàng)建Manager對象,
3.接著執(zhí)行下面的代碼,M3調(diào)用靜態(tài)方法Lookup。當(dāng)調(diào)用靜態(tài)方法時,JIT編譯器會定位到跟定義靜態(tài)方法相對應(yīng)的類型對象。然后,JIT編譯器定位到方法表的入口處。Lookup方法在堆上構(gòu)造了一個Manager對象并且返回該對象的地址。保存在變量e中,此時e不再指向開始new出來的那個Manager對象,開始的Manager對象已經(jīng)沒有變量引用它。在未來某個時候GC會對它進(jìn)行回收。
4.接著M3調(diào)用非虛方法的實例方法GetYearsEmployed,CLR會定位到與變量e類型一致的對象。(如果Employee沒有定義該方法,JIT編譯器會向上一層層查找直到Object。)
然后JIT編譯器定位到對象的方法表,這里可以看出相對于靜態(tài)方法多了一步定位。編譯該方法(如果之前沒有編譯過),調(diào)用編譯后的代碼。
5.接著M3調(diào)用虛方法實例方法GetProgressReport,調(diào)用時,JIT會生成一些額外的代碼,這些代碼在每一次方法調(diào)用時都會執(zhí)行,它會首先會查找發(fā)起調(diào)用的變量,然后跟隨地址來調(diào)用對象。這里的e變量執(zhí)行了Manager對象,生成的額外的代碼會檢查對象內(nèi)部的類型對象指針,該指針成員引用了實際的對象的類型。然后定位到對象的方法表,接著編譯。
?
?
注?? 《CLR via C#》(Jeffrey Richter著)——.NET 界的經(jīng)典之作,讀的過程寫點筆記跟大家分享,我也推薦大家看英文版,能夠直接領(lǐng)會原意 ?
轉(zhuǎn)載于:https://www.cnblogs.com/mszhangxuefei/archive/2012/07/24/clrnotes-4.html
總結(jié)
以上是生活随笔為你收集整理的new,is和as运算符解析及运行时类型,对象,线程堆栈,托管堆之间的联系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: form表单获取input对象浏览器区别
- 下一篇: ORA-00054: 资源正忙, 但指定