作者:黃季冬
發(fā)表時間:2008-02-25
第一回 真的了解 .NET Compact Framework嗎?
作為系列文章的開篇,有必要先詳細了解一下基于 CE.NET的 .NET Compact Framework(以后簡稱 .NET CF),本文敘述了 .NET CF的設(shè)計目標,架構(gòu)特征和執(zhí)行環(huán)境。
.NET CF的目標在哪里?
1. 專為設(shè)備設(shè)計的便攜式小型 .NET CLR
具有 .NET Framework的子集屬性,支持多種語言開發(fā)。我們知道,在英文里面“便攜式”對應(yīng)的單詞是 Portable,這個 Portable我們可以從兩方面理解:一方面, .NET CF工作在一個靈活的,移動的,資源有限的環(huán)境下;另一層意思則體現(xiàn)在 .NET CF本身的特性上,比如說它與 OS的寬松耦合, OS管與 CLR托管的不同就在這里。從編程的角度 Portable體現(xiàn)在很多“和諧”的方面,比如 I/O內(nèi)存映射,比如僅支持 Unicode編碼等等。
2. 與 Visual Studio系列 IDE高度兼容
不僅僅是編譯,調(diào)試托管和非托管的代碼,在 Visual Studio 2008中你還可以通過 Device Security Manager來為已連接的設(shè)備管理證書和設(shè)置安全級別。甚至可以編程訪問模擬器資源。
3. 與主機的操作系統(tǒng)有良好的共存性
這個共存性是多方面的,包括應(yīng)用程序的執(zhí)行模型,內(nèi)存管理,用戶輸入和 UI接口。這些在后面的文章中您都會接觸到。
當然還有一些要求是 .NET CF做不到的,暫時也不是它的目標,為了不使大家對 .NET CF的要求太“苛刻”,我覺得必須把這些“非目標”也列舉出來:
1. Compact VS. Full
.NET CF不是對桌面版本 .NET Framework的部分簡單平移,把 .NET Framework完整移植到移動設(shè)備上并不是 .NET CF的目標,盡管表面上看起來有些內(nèi)容和完整版的 .NET Framework是一致的,但是其實現(xiàn)方式可能很不一樣。
2. 實時性
Windows Mobile是一個 32位的民用操作系統(tǒng),你不能要求它和 VxWorks一樣工作!
.NET CF也并沒有提供對強實時性的支持 (問題是您真的需要那么高的實時性嗎? )。
3. 語言支持
.NET CF目前支持的開發(fā)語言并不像完整版本的那么豐富,目前比較流行的是 C/C++, C#和 VB。但是 .NET CF完全支持精簡版本的 ECMA CLI Profile,這意味著你也可以為更多的語言編寫針對 .NET CF的編譯器。
.NET CF的結(jié)構(gòu)模型
.NET CF 的架構(gòu)跟完整版的 .NET Fx有相似之處,同時又具有自己特色,如圖表 1所示。
圖表 1 .NET CF Architecture
最下面的是硬件層,由于圖幅有限,我僅列出了主要的一些硬件,而這所有的硬件都是由 Windows CE 操作系統(tǒng)所控制的, WinCE提供了內(nèi)存管理規(guī)范和用于加載可執(zhí)行文件的 Program Loader, Program Loader負責將可執(zhí)行文件 Push到內(nèi)存中并啟動它。當然, WinCE作為操作系統(tǒng)還有很多其他職能,比如線程管理,繪制窗體,相應(yīng)來自 GUI的事件,管理網(wǎng)絡(luò)連接等等。
作為使用 .NET CF的程序員,我們主要關(guān)注的是圖中虛線以上的部分,現(xiàn)在來看看 .NET CF 的 Common Language Runtime(CLR),圖中灰色背景的方框表示 .NET CF CLR。
用 Native Code(如 C/C++)編寫的基于 WinCE的程序,直接被編譯成 CPU可以識別的指令,但是依賴 WinCE去加載它們并提供所需的服務(wù)。而 CLR是一個用來托管應(yīng)用程序的平臺,托管的應(yīng)用程序被編譯成 Microsoft Intermediate Language(MSIL), IL在這里提供了一個與 CPU松耦合的機會, CLR根據(jù)不同的 CPU體系結(jié)構(gòu)將 IL編譯成不同的 CPU指令,這一點在行為上與桌面版的 CLR是一致的。
有一點要弄清的是托管的 EXEs或者 DLLs是由 IL構(gòu)成的,并不能被 CPU直接執(zhí)行,而是需要被 CLR編譯成適用于本地 CPU的指令或者是本地代碼。可見, CLR的工作是執(zhí)行托管代碼,這個過程就是托管代碼本地化并被執(zhí)行的過程,簡單來講,它包括以下步驟:
1. 將 IL從文件系統(tǒng)加載到內(nèi)存中。
2. 這些 IL中的部分或全部將被轉(zhuǎn)化成本地代碼供 CPU執(zhí)行
3. 如果這些 IL引用了某些 DLL的內(nèi)容,則當 DLL被找到并正確加載后,這些被用到的部分也會被轉(zhuǎn)化成本地代碼并被執(zhí)行。
可見這個 Just In Time Compiler在 CLR的運行中扮演著十分重要的角色。在 .NET Compact Framework中有兩種形式的 JIT編譯器, iJIT和 sJIT:
iJIT適用于所有的 CPU,如 ARM, MIPS, SHx和 X86等。 iJIT較簡單,編譯的速度也比較快,但是它編譯出來的本地代碼并不像 sJIT那樣經(jīng)過優(yōu)化的。
sJIT編譯器是 ARM指令體系下特有的,它充分利用了 AMR處理器的優(yōu)勢。雖然編譯速度不及 iJIT,但是編譯后的代碼在第二次運行的時候會迅速得多。
所以在編寫應(yīng)用程序的時候你應(yīng)當考慮到你的程序是否是專為基于 ARM的設(shè)備而設(shè)計,或是有考慮到用戶的機器可能是一臺性能一般的 MIPS。
默認狀況下,僅當無法使用 sJIT Compiler的時候, CLR才會選擇使用 iJIT的方式。這樣做的原因是,通常在程序執(zhí)行過程中,花在 JIT編譯上的時間和執(zhí)行程序的時間相比是微不足道的。
需要注意的是在我們的程序當中應(yīng)當避免額外的 JIT行為,因為有些情況下,這會明顯影響到應(yīng)用程序的運行速度,當然,要做到這一點需要您對 CLR有一定的認識。 JIT按需編譯,并嘗試對編譯后的代碼在程序生命周期內(nèi)進行保留,這樣下一次調(diào)用的時候就不必再執(zhí)行 JIT了。說是嘗試是不考慮內(nèi)存的緣故,這樣的緩存不會無限制的進行下去,當內(nèi)存不夠用時, CLR會逐方法的將 JIT過的代碼清除掉,這就是所謂的 Code Pitching。清除掉之后再次調(diào)用該方法 CLR就會重新進行 JIT編譯。有趣的是這個 Pitch的過程也是智能化的,哪些最不常用的方法的 JITed Code會被最先清除。
如果我們的程序編寫不當,在某些極端情況下,重復的 JIT可能會出現(xiàn)在一個循環(huán)中,每一次循環(huán)都將重新 JIT一次,這顯然會使性能大打折扣,而且很可能使你的程序因此 down掉。
性能問題在今后的文章中還會專門介紹。
用一句話概括圖表 1,可以說“是 .NET CF CLR使得 .NET應(yīng)用程序得以運行在各種不同的基于 Windows CE.NET的移動設(shè)備上”。
Compact CLR VS. Full CLR
對于習慣了桌面應(yīng)用的程序員,有必要了解一下精簡版的 .NET CF與完成版本的 .NET CF有哪些不同。
首先從體系結(jié)構(gòu)上, .NET CF CLR與桌面版本的 CLR不盡相同。從圖表一我們看到, .NET CF CLR 構(gòu)建在 Platform Abstraction Layer(PAL)之上, PAL位于執(zhí)行引擎與 OS之間,將 CLR從硬件的層面抽象出來,如果您需要將 CLR移植到其他平臺,只需要改變 PAL層,并為該平臺的 CPU編寫相應(yīng)的 JIT Compiler。正是這種靈活性,使得 .NET CF CLR也隨著日新月異的 Mobile硬件設(shè)備不斷前行。
在 JIT編譯之后, .Net CF CLR對生成的本地代碼的處理也與桌面版本不同。在桌面版本的 CLR中, JIT過后的代碼有時候會在程序退出之后依然存在,這樣在它下次加載的時候會快一些。但是 .Net CF CLR僅僅在程序運行期間保存 JIT生成的代碼。每一次程序啟動, JIT編譯必然再次發(fā)生。
在對程序集的定義上面, .Net CF CLR和桌面版本的 CLR也有所不同,桌面版本的程序集支持多文件構(gòu)成一個程序集。而 .NET CF CLR不支持這一性質(zhì),這在移植桌面應(yīng)用程序到 .NET CF下的時候是需要注意的。
這些不同都是與移動設(shè)備本身的特性密不可分的,如果您要了解更多 .NET CF與 .NET Framework的不同,請參照這里
.Net CF應(yīng)用程序的執(zhí)行環(huán)境
我們通常在調(diào)試程序的時候主要有兩種執(zhí)行環(huán)境 ---模擬器和真實設(shè)備。要注意,這里模擬器并不是說就是在 Windows(x86)下面工作的用來模仿基于 WinCE操作系統(tǒng)行為的一個程序,而是一個真正的 CE.NET或者 Windows Mobile操作系統(tǒng)的鏡像,只是它是由 x86的操作系統(tǒng)所編譯并運行。而在真實設(shè)備上運行的程序則是 .NET CF CLR所掌管的一個實例。
前面講 JIT的時候已經(jīng)提到過應(yīng)用程序的執(zhí)行了。我們說“是 .NET CF CLR使得 .NET應(yīng)用程序得以運行在各種不同的基于 Windows CE.NET的移動設(shè)備上”。 CLR無疑是 .NET最重要的組成部分,它負責將已編譯成 MSIL的托管程序集裝配到應(yīng)用程序域中,以 JIT的編譯方式將他們編譯成本地代碼供宿主 CPU執(zhí)行, 同時它還要在運行過程中管理內(nèi)存分配,垃圾回收以及加載其他類庫等。
從組成上可以把 .NET CF CLR分成兩部分:執(zhí)行引擎和基礎(chǔ)類庫。
執(zhí)行引擎與底層操作系統(tǒng)提供的各種服務(wù)接口打交道 (這離不開 PAL的作用 ),而基礎(chǔ)類庫則是構(gòu)成 .NET應(yīng)用程序的基本程序單元。
其中基礎(chǔ)類庫發(fā)展到現(xiàn)在已經(jīng)十分豐富,想必大家也比較熟悉,在此無需也無法作多的介紹。下面看看執(zhí)行引擎 (Execution Engine)。
執(zhí)行引擎為托管代碼的執(zhí)行提供了眾多基本服務(wù),比如:
Ø 程序集的 Loader和全局程序集緩存 (GAC)
元數(shù)據(jù)引擎 /緩存
對類層次模型的描述
“反射”技術(shù)
(關(guān)于程序集的加載,后續(xù)的文章中也會介紹 )
Ø JIT的編譯和校對機制
Ø 安全的執(zhí)行體系
異常探知 ,
本地代碼互操作 ,
OS安全性保障
Ø 垃圾回收器
Ø 對調(diào)試的支持
為 Debug版本的程序生成可方便調(diào)試 (如斷點 )的代碼
Ø 對某些托管的 API(Class Libs)采用本地化的實現(xiàn)
執(zhí)行引擎 (EE)是 .NET的核心組件,它掌管著 .NET CF的所有其他東西。其本身是一個本地可執(zhí)行的文件,它通過平臺抽象層 (PAL)與底層操作系統(tǒng)進行交互,他們共同被安置在一個可執(zhí)行文件中 (Mscoree.dll),你可以在 Windows/System32目錄下面找到它。
PAL層 (the Platform Adaptation Layer)就如同基于 WinNT的操作系統(tǒng) (Windows NT 4.0, 2000, XP, 2003)的硬件適配層 (HAL),用于在常規(guī)代碼和不同硬件水平的 CPU之間做一個適配。正是 PAL的存在,使得 .NET CF的程序集能運行在使用任何 CPU的任何 WinCE兼容的設(shè)備上,而以往用經(jīng)典的 EVC開發(fā)的應(yīng)用程序可能還需要為不同的 OS和 CPU單獨編譯。 ,
另外,.NET CF同樣支持 GAC,你可以以可復用的方式部署你的應(yīng)用程序,它是通過預加載某些基礎(chǔ)類庫,你可以在你的應(yīng)用中通過應(yīng)用的方式來調(diào)用他們,這樣減少了代碼量,也提高了性能。
在異常處理方面, .NET CF還有一個有趣的特點,我們知道,通常一個 error發(fā)生的時候,一條錯誤消息會隨之而來,開發(fā)者可以捕獲到這個消息,并選擇怎么處理。在 .NET CF中,基于對內(nèi)存問題的考慮,微軟摘錄了所有這些錯誤信息,并為各種支持的語言把它們分別單獨放在一個字符串文件中 (SYSTEM.SR.dll),部署的時候,你可以選擇是否將這些錯誤信息文件隨你的應(yīng)用程序一同部署到設(shè)備上。當然選擇不部署這個文件在 load的時候會節(jié)省一些性能,在這篇文章也有提到這個問題。
之前一再提到 Portable這個詞,設(shè)備是 Portable的, .NET CF也是 Portable的,移植到新的平臺只需重新編寫 JIT Compiler和 PAL層,執(zhí)行引擎是無需改變的,不同的 PAL導致了 MSCoree.dll不同的實現(xiàn)方式。執(zhí)行引擎用標準 C語言編寫,這也是 Portable的體現(xiàn)。
總結(jié)
.NET Compact Framework使得熟悉 .NET Framework的程序員得以用他們熟知的 C#或者 VB來開發(fā)移動設(shè)備上的程序。
.NET CF 和完整版的 .Net Framework不單純是子集關(guān)系。開發(fā)的時候除了要注意,用戶可能使用不同處理器,還應(yīng)考慮到 PPC與 PC的區(qū)別, Smartphone與 PPC的區(qū)別。
.NET CF CLR(the CLR Designed for .NET Compact Framework)是專為設(shè)備設(shè)計的代碼托管運行機構(gòu),在垃圾回收機制,異常處理和安全性等方面繼承了 .NET托管應(yīng)用程序的優(yōu)勢。同時它又有自身的特性,比如 PAL。兩種 JIT的方式中, sJIT是僅適用于 ARM處理器的。
執(zhí)行環(huán)境方面, MSCoree.dll是應(yīng)用程序執(zhí)行的基礎(chǔ),它由執(zhí)行引擎 (EE)和平臺抽象層 (PAL)構(gòu)成。
對于 .NET CF 3.5中的新特性,可以參考這里
聯(lián)系客服