posts - 80,comments - 749,trackbacks - 2
          標(biāo)題: CLR和JRE的運(yùn)行機(jī)制的初步總結(jié) 引用回復(fù) 將這個帖子加入我的Blog

          概念比較:
          Java C#
          byte code IL(字節(jié)碼,中間語言)
          jvm.dll mscrolib.dll,mscrojit.dll(虛擬機(jī))
          JRE CLR(運(yùn)行環(huán)境)
          JDK .Net Framework(開發(fā)框架)
          package assembly(類庫,程序集)


          一、關(guān)于類庫的版本管理問題

          Java和C#代碼運(yùn)行要依靠其運(yùn)行環(huán)境(JRE,CLR)和運(yùn)行環(huán)境帶的基礎(chǔ)類庫(C#稱為配件或者程序集Assembly),此外還會有一些第三方的 類庫或者自己開發(fā)的類庫。如果運(yùn)行環(huán)境版本不一致,或者引用的類庫版本不一致都會帶來程序不能正常運(yùn)行。比如一個Java程序是在JDK1.2上開發(fā),如 果在JRE1.4上運(yùn)行,一般情況下可以向下兼容,但也有例外,有些GUI程序在JDK1.4上面運(yùn)行結(jié)果很可能會不同。

          JRE的版本管理

          Java的解決辦法是每個程序自己攜帶一套JRE。
          我的機(jī)器上已經(jīng)被安裝了好多套JRE和JDK了(JDK包括了同版本的JRE,此外還包括有編譯器和其它工具),它們分別是:
          BEA Weblogic Server 7.0 自帶一套 JDK1.3.1_02
          我下載了一套最新的JDK1.4.1_02
          JBuilder9自帶一套JKD1.4.1_02
          Oracle8.1.7自帶一套JRE1.1.7
          Ration Rose自帶一套JDK1.3
          DreamWeaver自帶一套JDK1.3
          6套JRE,每套JRE都被各自安裝到不同的目錄,不會互相影響。當(dāng)在控制臺執(zhí)行java.exe,操作系統(tǒng)尋找JRE的方式如下:
          先找當(dāng)前目錄下有沒有JRE
          再找父目錄下有沒有JRE
          接著在PATH路徑中找JRE
          注冊表HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\ 查看CurrentVersion的鍵值指向哪個JRE
          最常用的是在PATH路徑中找JRE,一般情況下,自己的程序運(yùn)行之前都會先在批處理文件里面臨時設(shè)置PATH,把自己用的JRE放到PATH路徑最前面,所以肯定會運(yùn)行自己帶的JRE,不會造成版本混亂。

          .Net Framework的版本管理

          .Net Framework被固定安裝在C:\Winnt\Microsoft.NET\Framework\v版本號\目錄下,聽說剛發(fā)行的.Net Framework1.1已經(jīng)對1.0做了很多改進(jìn),也許在舊版本的.Net Framework開發(fā)的程序在往新版本上面遷移的時候需要部分修改。



          JRE的基礎(chǔ)類庫

          JRE自帶的基礎(chǔ)類庫主要是JRE\lib\rt.jar這個文件,包括了Java2平臺標(biāo)準(zhǔn)版的所有類庫。和JRE的版本一致。

          .Net Framekwork的核心類庫

          .Net Framekwork的核心類庫被放置在C:\Winnt\assembly\gac\目錄下,按照不同的名稱空間放在不同目錄中,不像JRE打成了一個包。并且可以同時存在不同的版本,例如:
          某類庫1.0版本 C:\Winnt\assembly\gac\名稱\1.0\名稱.dll
          某類庫1.1版本 C:\Winnt\assembly\gac\名稱\1.1\名稱.dll
          這樣做,雖然很靈活,可以隨時把類庫更新到最新的狀態(tài),但是很容易帶來版本管理的復(fù)雜度,造成版本不一致。



          JRE類庫的查找方法和版本管理

          JRE中由ClassLoader負(fù)責(zé)查找和加載程序引用到的類庫,基礎(chǔ)類庫ClassLoader會到rt.jar中自動加載,其它的類庫, ClassLoader在環(huán)境變量CLASSPATH指定的路徑中搜索,按照先來先到的原則,放在CLASSPATH前面的類庫先被搜到,Java程序啟 動之前建議先把PATH和CLASSPATH環(huán)境變量設(shè)好,OS通過PATH來找JRE,確定基礎(chǔ)類庫rt.jar的位置,JRE的 ClassLoader通過CLASSPATH找其它類庫。但有時候會出現(xiàn)這樣的情況,希望替換基礎(chǔ)類庫中的類庫,那么也可以簡單的通過- Djava.endrosed.path=...參數(shù)傳遞給java.exe,于是ClassLoader會先于基礎(chǔ)類庫使用 java.endrosed.path參數(shù)指定路徑的類庫。因此Java的版本管理是非常簡單有效的,也許很原始,不過很好用,簡單就不容易出錯。(所以 我很奇怪Eric Ramond為什么批評Java的類庫管理機(jī)制,他還居然批評Java的接口,令人懷疑他對Java的了解程度)

          .Net Framework的類庫管理機(jī)制

          .Net Framework的類庫管理機(jī)制相當(dāng)強(qiáng)大和復(fù)雜,分為私有類庫和共享類庫。
          私有類庫就放在exe程序當(dāng)前路徑下,或其相對路徑中,只有當(dāng)前程序可見。
          共享類庫需要在GAC(Global Assembly Cache)中注冊,注冊過程比較復(fù)雜,首先要用工具生成公開/私有密鑰對,然后結(jié)合密鑰和類庫版本號連編,最后使用工具注冊到GAC中好以后,會被放在 "C:\Winnt\assembly\gac\類庫的名稱空間\版本號\"目錄下,不同的類庫版本在注冊的時候會按照版本號分開放置:
          某類庫1.0版本 C:\Winnt\assembly\gac\名稱\1.0\名稱.dll
          某類庫1.1版本 C:\Winnt\assembly\gac\名稱\1.1\名稱.dll

          也就是可以同時存在一個類庫的n個版本,至于在程序中用哪個版本,在程序的配置文件中聲明,CLR會根據(jù)聲明來調(diào)用相應(yīng)的版本的類庫。我覺得.Net實現(xiàn) 方法未免太復(fù)雜了一些,將所有共享類庫都塞到一個系統(tǒng)目錄下,并且同一個類庫還有n個版本,將來.Net第三方開發(fā)的類庫逐漸豐富起來以后,.Net類庫 的GAC也會越來越龐大,會不會也搞得和Windows注冊表一樣難以維護(hù)?軟件發(fā)布到服務(wù)器上的時候,類庫要再注冊一次,服務(wù)器會逐漸形成一個龐大的樹 狀的GAC,GAC里面存放著組件的n個版本。試想經(jīng)過一段時間之后,C:\Winnt\assembly\gac\目錄會越來越龐大,有的組件甚至有n 個版本都放在那里,你又不敢隨便刪除,不知道是不是有程序需要使用,我不明白MS為什么要把這么簡單的事情搞到這么復(fù)雜?


          綜上所述,Java的版本管理方式簡單而有效,C#的版本管理方式功能強(qiáng)大,不過是不是太復(fù)雜了?會不會搞成第二個注冊表一樣的東西?



          二、虛擬機(jī)啟動和加載類庫的方式


          Java的虛擬機(jī)啟動和加載類庫

          在Console執(zhí)行java.exe xxx命令以后,如前所述的尋找JRE,OS找到JRE目錄,根據(jù)java.exe的傳遞參數(shù),選擇加載Server版的jvm.dll還是Client版的jvm.dll,然后加載jvm.dll,把控制權(quán)交給jvm.dll。

          接下來,jvm.dll進(jìn)行初始化,分配內(nèi)存等等動作,然后在CLASSPATH路徑中尋找class,找到class以后,尋找class中的程序入口 點Main函數(shù),然后從Main函數(shù)執(zhí)行程序,在執(zhí)行過程中,使用ClassLoader動態(tài)加載一系列引用到的類。當(dāng)調(diào)用到native方法時, jvm.dll告訴OS在JRE\bin目錄下尋找某某DLL文件,調(diào)入內(nèi)存,于是實現(xiàn)了JNI調(diào)用。


          .Net的虛擬機(jī)的啟動推測

          我對.Net的虛擬機(jī)的啟動過程還一知半解,自己寫了一些例程,并且用內(nèi)存工具來檢測觀察,推測.Net的運(yùn)行機(jī)制,先來拋磚引玉,請熟悉Windows平臺編程的朋友指教。.Net有3個目錄中的文件在執(zhí)行的時候會被加載

          1、C:\WINNT\Microsoft.NET\Framework\v版本號\
          該目錄下的mscorlib.dll,mscorrsn.dll,mscorwsk.dll,mscorjit.dll是核心DLL,大概是運(yùn)行虛擬機(jī)的 必要文件,其中mscrolib.dll是入口點。此外,該目錄下還有一些.Net的System名稱空間的IL類庫,與C:\Winnt\ assembly\gac\相應(yīng)目錄下的IL類庫完全一樣,這些是最核心的基礎(chǔ)類庫。.Net的編譯器,檢查器等等工具軟件也在該目錄,推測System 名稱空間的核心類庫之所以在這個目錄下copy一份是因為作為.Net的編譯器等工具的私有類庫之用。

          2、C:\Winnt\assembly\gac\
          該目錄下放置.Net共享類庫,如前所述

          3、C:\Winnt\assembly\nativeimages_.Net版本號\
          在該目錄下也有一些以System名稱空間開頭的核心類庫,推測是MS為了加快CLR的執(zhí)行效率把核心類庫進(jìn)行本地化,編譯為native image的同名DLL。可以觀察到該目錄下的同名DLL文件,比GAC目錄下的同名DLL文件體積大,可能是因為link底層DLL庫的緣故。
          某核心類庫 C:\Winnt\assembly\nativeimages_.Net版本號\名稱空間\.Net版本號_散列碼\名稱.dll

          另外值得注意的地方是有兩個mscorlib.dll
          1、C:\WINNT\Microsoft.NET\Framework\v版本號\mscrolib.dll (1.88MB)
          2、C:\WINNT\assembly\NativeImages1_v版本號\mscorlib\版本號__散列碼\mscrolib.dll (3.07MB)
          mscrolib.dll (1.88MB)還是一個IL碼的版本,所以映射了一個native的版本的mscrolib.dll (3.07MB),來加快CLR的速度。


          當(dāng)IL的exe程序被雙擊執(zhí)行時,OS Loader讀入程序,識別出是IL,根據(jù)IL內(nèi)部的引用定義,加載mscorlib.dll,而mscorlib.dll也是IL,內(nèi)部引用C:\ winnt\system32\mscoree.dll,于是再加載mscoree.dll,然后把控制權(quán)交給mscoree.dll, mscoree.dll接著加載mscrorsn.dll,mscrowsk.dll,mscrojit.dll,為了加快mscorlib.dll的調(diào) 用,加載mscorlib.dll的native image版本,然后由mscorlib.dll接管控制權(quán)(不知道這兩個mscorlib.dll是如何來上管IL,下連native code的?)最后尋找IL碼程序的入口點Main函數(shù),開始執(zhí)行程序,在執(zhí)行過程中,使用Class Loader動態(tài)加載一系列引用到的類,在當(dāng)前路徑下,在共享類庫的GAC中查找等等。

          這里和jvm.dll不同的一點是,jvm.dll加載的基礎(chǔ)類庫和加載其它類庫方式完全一樣,全部都是字節(jié)碼的class。而mscrolib.dll 加載以System名稱開頭的核心類庫的時候,使用了“不正當(dāng)競爭手法”。mscrolib.dll從GAC中加載共享核心類庫之后,又C:\Winnt \assembly\nativeimages_.Net版本號\名稱空間\ 目錄下加載了核心類庫的native版本,這樣一來,自然CLR運(yùn)行起來要快多了。特別是圖形圖像類庫全部都有native映射版本,所以CLR上運(yùn)行 GUI焉能不快?

          對比CLR和JRE的加載過程,比較不同的地方是mscorlib.dll和System核心類庫都有一個native image,可能這是CLR運(yùn)行速度比較快的一個主要原因吧。

          分析完以后有一個特別明顯的感受,Java的底層運(yùn)行機(jī)制設(shè)計的特別簡單,而.Net的底層運(yùn)行機(jī)制設(shè)計的特別復(fù)雜。但是在企業(yè)層剛好相反,J2EE設(shè)計的特別復(fù)雜,而.Net卻設(shè)計的特別簡單,真是有意思!

          Java的底層機(jī)制設(shè)計雖然簡單,但是很健壯,.Net設(shè)計使得它的CLR速度快,類庫管理功能強(qiáng)大,但是不是比Java更優(yōu)秀,還要等以后慢慢看了。

          RE:

          我查了一下《.Net Essential》這本書,上面提到這樣的說法。

          MS更新了Windows各個版本的OS Loader程序,使得OS Loader可以識別.Net PE格式的exe文件,當(dāng)執(zhí)行Windows Native PE格式的exe文件的時候,OS Loader按照以往的方式加載系統(tǒng)DLL。如果是.Net PE格式的exe文件,OS Loader加載mscorlib.dll,然后把控制權(quán)交給mscorlib.dll。

          posted on 2005-03-28 11:22 Brian Sun 閱讀(478) 評論(0)  編輯  收藏 所屬分類: 軟件轉(zhuǎn)貼
          主站蜘蛛池模板: 苏尼特右旗| 商城县| 淮安市| 句容市| 尖扎县| 东光县| 正蓝旗| 德州市| 即墨市| 漯河市| 托克托县| 龙江县| 福海县| 祥云县| 恩平市| 明光市| 司法| 华蓥市| 治县。| 石楼县| 巴南区| 芮城县| 遂川县| 疏勒县| 顺平县| 汝南县| 牟定县| 昌江| 阿尔山市| 穆棱市| 三明市| 佳木斯市| 平舆县| 项城市| 东明县| 启东市| 抚顺市| 秀山| 巴南区| 建平县| 中阳县|