菜鳥CLR VIA C#之旅(1):品味細(xì)節(jié),CLR的執(zhí)行模型從菜鳥剛接觸到.net時,,菜鳥就知道CLR VIA C#是一本很牛的書,為什么,?CSDN會告訴你——總會有人問“學(xué).net什么書籍好,?”,這個本沒有標(biāo)準(zhǔn)答案的問題,,菜鳥卻從各種大牛一致的回答中找到了標(biāo)準(zhǔn)答案:C#入門經(jīng)典—>C#高級編程—>CLR VIA C#,于是乎,,對于大牛們的信任,這三本書都躺在菜鳥的床頭,。雖然菜鳥很菜,,但菜鳥喜歡在CDSN、博客園,、codeproject(菜鳥英語不堪忍睹,,每次都還需要打開Google翻譯)上閑逛,屬于那種不厚道的看帖不回帖的一員,,甚至過了相當(dāng)長的一段時間都還沒有注冊,,不是菜鳥不想回答,而是菜鳥水平實在不堪忍睹,,怕誤導(dǎo)人家,,更怕關(guān)公面前耍大刀。菜鳥發(fā)現(xiàn)自己錯了,,為什么,?你懂的!為此在大三暑假的時候,,菜鳥在CSDN上走火入魔似的回答了別人一個月的問題,,即時菜鳥不會的(其實大多都不會),菜鳥會去翻書,、找度娘,、搜谷姐,想盡辦法幫別人回答,,一個月后菜鳥的等級竟然有一顆星星了,,當(dāng)時激動的跑到灌水區(qū)散了下分,,但之后菜鳥又回到了看帖不回帖的狀態(tài),或許是開學(xué)了,,或許是DOTA去了,,或許是沒激情了,反正具體什么原因已記不清楚,。
“紙上得來終覺淺,,須知此事要躬行”,如果僅僅是看別人的文章或書籍,,可能就在看的時候有感覺,,合上之后就什么也不記得了,所以菜鳥決定將自己看到的或?qū)W到的好東西記錄下來——不再為看不懂高深的技術(shù)文章而煩惱,,而是拿起《CLR VIA C#》踏踏實實從頭到底邊閱讀邊寫筆記,。
在菜鳥上篇菜鳥CLR VIA C#之旅—開始旅行:千里之行始于足下完成后,得到了很多大牛們的支持,,在此菜鳥深表感謝,,更要謝謝那些提出意見的高手們,志志同學(xué)首先發(fā)了了菜鳥一個低級的錯誤,,“將Hello world寫成了Hello word”,,當(dāng)時馮同學(xué)的一句“啥時候出一片 Hello,excel! 啊,?”我還疑惑不解,,哎,太粗心了,。對于 toEverybody的留言:“又要人在研究C#編譯器產(chǎn)生的亂碼呀//唉....”菜鳥不敢茍同,但從這個留言中可以看出,,很多的園友都把目光和焦點注意在如何理解IL代碼這個問題上,。這真是個莫大的好消息,因為很明顯大家的思路慢慢的從應(yīng)用向底層發(fā)生著轉(zhuǎn)變,,技巧性的東西是一個方面的積累,,底層的探索為也是必不可少的修煉(anytao)。 對于.NET程序員來說,,IL代碼意味著: 通用的語言基礎(chǔ)是.NET運行的基礎(chǔ),,當(dāng)我們對程序運行的結(jié)果有異議的時候,如何透過本質(zhì)看表面,,需要我們從本質(zhì)入手來探索,,這時 IL是你必須知道的基礎(chǔ); 元數(shù)據(jù)和IL語言是CLR的基礎(chǔ),,了解必要的中間語言是深入認(rèn)識CLR的捷徑,; 大量的事例分析是以IL來揭密的,,因此了解IL是讀懂他人代碼的必備基礎(chǔ),可以給自己更多收獲,。 很明顯這些優(yōu)越性足以誘惑我們花時間和精力涉獵其中,。然而,了解了IL的好處,,并不意味著我們應(yīng)該過分的來關(guān)注IL,,有人甚至可以洋洋灑灑的寫一堆IL代碼來實現(xiàn)一個簡單Hello world程序,但是正如我們知道的那樣,,程序設(shè)計已經(jīng)走過了幾十年的發(fā)展,,如果純粹的陶醉在歷史中,除了腦子不好,,沒有其他的解釋,。不然看見任何代碼都以IL的角度來分析,又將走進(jìn)另一個誤區(qū),,我們的宗旨是追求但不過分,。
好了,開始《CLR VIA C# 》第一章 “CLR的執(zhí)行模型”的學(xué)習(xí),,了解下應(yīng)用程序是如何執(zhí)行的,。如果能清楚的了解代碼是如何運行的,菜鳥認(rèn)為對于以后代碼的調(diào)試和優(yōu)化將起到關(guān)鍵作用,。
1 將源代碼編譯成托管模塊只要編譯器是面向CLR的任何語言,,其創(chuàng)建的源代碼,都會用一個對應(yīng)的編譯器來檢查語法和分析源代碼,,最終結(jié)果都是生成一個托管模塊(managed module),。
托管模塊 托管模塊是一個標(biāo)準(zhǔn)的32位Microsoft Windows可移植執(zhí)行體(PE32)文件,或者是一個標(biāo)準(zhǔn)的64位Windows可移植執(zhí)行體(PE32+)文件,,它們都需要CLR 才能執(zhí)行,。順便說一句,托管的程序集總是利用了Windows的數(shù)據(jù)執(zhí)行保護(hù)(Data Execution Prevention,,DEP)和地址空間布局隨機化(Address Space Layout Randomization,,ASLR);這兩個功能旨在增強整個系統(tǒng)的安全性,。托管模塊包括以下幾個部分:
1)PE32或PE32+頭:PE32能在windows32位或64位機器上運行,,PE32+只能在64位機器上運行。 2)CLR頭:包含了需要的CLR版本,,一些flag,,托管模塊入口方法(Main方法)以及各種信息。 3)IL(中間語言)代碼:編譯器編譯源代碼后生成的代碼,,在運行的時候,,CLR再將IL編譯為本地CPU指令,。 4)元數(shù)據(jù):每個托管模塊都包含元數(shù)據(jù)表,有兩種類型,,一種類型的表描述源代碼中定義的類型和成員,,一種類型的表描述源代碼中引用的類型和成員。
元數(shù)據(jù)的用途: 在編譯時,,元數(shù)據(jù)消除了對頭和庫文件的需求,。 VS的“智能感知功能”就是依靠元數(shù)據(jù)來解譯一個類型提供了什么方法、屬性,、事件和字段,。如果是一個方法將是傳入的參數(shù)。 IL的“安全”檢查需要元數(shù)據(jù),。 元數(shù)據(jù)可以對一個對象的代碼序列化,,存入到內(nèi)存,發(fā)生到另一臺機器上,??梢栽诹硪慌_機器上進(jìn)行反序列化來重建對象狀態(tài)。 元數(shù)據(jù)可以運行垃圾收集器跟蹤對象的生存期,。
2 將托管模塊合并成程序集
在這幅圖中,一些托管模塊和資源(或數(shù)據(jù))文件準(zhǔn)備交由一個工具處理,。該工具生成單獨一個PE32(+)文件來表示文件的邏輯性分組。實際發(fā)生的事情是,,這個PE32(+)文件包含一個名為“清單”(manifest)的數(shù)據(jù)塊,。清單是由元數(shù)據(jù)表構(gòu)成的另一種集合。這些表描述了構(gòu)成程序集的文件,,由程序集中的文件實現(xiàn)的公開導(dǎo)出的類型,,以及與程序集關(guān)聯(lián)在一起的資源或數(shù)據(jù)文件。
程序集的類型 既可以生成單文件程序集,,也可以生成多文件程序集,,取決于你對于編譯器或工具的選擇,。
程序集清單中的內(nèi)容
3 加載公共語言運行時每個程序集既可以是一個可執(zhí)行應(yīng)用程序,,也可以是一個DLL,但最終都是由CLR管理這些程序集中代碼的執(zhí)行,, 這意味著必須在目標(biāo)機器 上安裝好.NET Framerwork. 要知道是否已安裝.Net Framework,,只需檢查%SystemRoot%System32目錄中的MSCorEE.dll文件。存在該文件,,表明.Net Framework已安 裝,。 .NET Framework SDK提供了一個名為CLRVer.exe的命令行實用程序,它能列出一臺機器上安裝的所有CLR版本,比如菜鳥電腦上:
4 執(zhí)行程序集的代碼 托管程序集同時包含元數(shù)據(jù)和IL,,IL是與CPU無關(guān)的機器語言,,為了執(zhí)行一個方法,必須把它的IL轉(zhuǎn)換成本地CPU指令,。 方法的第一次調(diào)用:
Main方法首次調(diào)用WriteLine時: JITCompiler函數(shù)被調(diào)用,,它知道要調(diào)用的是哪個方法,以及具體是什么類型定義了該方法 JITCompiler會在定義(該類型的)程序集的元數(shù)據(jù)中查找被調(diào)用的方法的IL,。 JITCompiler驗證IL代碼,,并將IL代碼編譯成本地CPU指令。本地CPU指令被保存到一個動態(tài)分配的內(nèi)存塊中。 JITCompiler返回CLR為類型創(chuàng)建的內(nèi)部數(shù)據(jù)結(jié)構(gòu),,找到與被調(diào)用的方法對應(yīng)的那一條記錄,,修改最初對JITCompiler的引用,讓它現(xiàn)在指向內(nèi)存塊(其中包含了剛才編譯好的本地CPU指令)的地址,。 JITCompiler函數(shù)跳轉(zhuǎn)到內(nèi)存塊中的代碼,。這些代碼正是WriteLine方法(獲取單個String參數(shù)的那個版本)的具體實現(xiàn)。這些代碼執(zhí)行完畢并返回時,,會返回Main中的代碼,,并跟往常一樣繼續(xù)執(zhí)行。
一個方法只有在首次調(diào)用時才會有一些性能損失,,以后對該方法的調(diào)用都以本地代碼的形式全速運行,無需重新驗證IL并把它編譯成本地代碼,。 一旦應(yīng)用程序終止,,編譯好的代碼也會被丟棄,所以再次運行,,JIT編譯器必須再次將IL編譯成本地指令,。
最后,了解下通用類型系統(tǒng)(Common Type System,,CTS)以及公共語言規(guī)范(Common Language Specificcation,,CLS)CLR是完全圍繞類型展開的,而了解類型則有必要把焦點放在.NET類型體系的公共基礎(chǔ)架構(gòu)上,,由于通用類型系統(tǒng)的存在,,.NET平臺下的各種語言可以無縫的集成,從MSDN的官方解釋上我們可以看到: 通用類型系統(tǒng)定義了如何在運行庫中聲明,、使用和管理類型,,同時也是運行庫支持跨語言集成的一個重要組成部分。通用類型系統(tǒng)執(zhí)行以下功能:
我們都知道CTS支持兩種基本的類型:值類型和引用類型,至于他們之間的區(qū)別,,這不是本節(jié)的主要內(nèi)容,,以后會詳細(xì)剖析.
菜鳥從anytao那里學(xué)習(xí)到: .NET技術(shù)可以以規(guī)范和實現(xiàn)兩部分來劃分,,而我們經(jīng)常強調(diào)和提起的.NET Framwork,,主要包括公共語言運行時(Common Language Runtime, CLR)和.NET框架類庫(Framework Class Library, FCL),其實是對.NET規(guī)范的實現(xiàn),。而另外一部分:規(guī)范,,我們稱之為公共語言架構(gòu)(Common Language Infrastructure, CLI),主要包括通用類型系統(tǒng)(CTS),,公共語言規(guī)范(Common Language Specification, CLS)和通用中間語言(Common Intermediate Language, CIL),。我們以圖的形式來看看CTS在.NET技術(shù)陣營中的位置。
要和其他對象完全交互,而不管這些對象是以何種語言實現(xiàn)的,,對象必須只向調(diào)用方公開那些它們必須與之互用的所有語言的通用功能,。為此定義了公共語言規(guī)范 (CLS),它是許多應(yīng)用程序所需的一套基本語言功能,。CLS 規(guī)則定義了通用類型系統(tǒng)的子集,,即所有適用于通用類型系統(tǒng)的規(guī)則都適用于 CLS,除非 CLS 中定義了更嚴(yán)格的規(guī)則,。 題外話 不要過于專著于技術(shù),,這里的技術(shù)指工作中用于開發(fā)的技術(shù)。在幾年之后,,當(dāng)你只有.NET可以和你的孩子分享的話,,是不是太可悲了。在軟件行業(yè),,技術(shù)雖然一定程度決定了薪水,、決定了職位,但是我們的生活并不是100%是工作,,有時間為技術(shù)而發(fā)愁,,為何不綜合提升自己的其它能力呢?并且隨著職位的上升,,往往溝通能力,、經(jīng)濟(jì)知識以及文學(xué)藝術(shù)修養(yǎng)比技術(shù)顯得更重要,這個時候嘆息自己過于專著技術(shù)往往為時過晚,。l 學(xué)習(xí)靠自己,,不要期望別人教你什么,,學(xué)習(xí)要主動; l 不管水平高低,,不要看不起自己,,也不能看不起別人,學(xué)習(xí)要心態(tài)好,; l 不能不思進(jìn)取,也不用讓自己為技術(shù)所累,,給自己多一點技術(shù)之外的時間,; l 如果時間不充裕,優(yōu)先考慮學(xué)習(xí)基礎(chǔ)的內(nèi)容,,同時也可以多關(guān)注一些新的思想,; l 如果別人能從你這里學(xué)到知識的話,那么你自己也一定學(xué)到了知識,,請堅持分享,。 |
|