天天看點

Windows Mobile 進階系列.第一回.真的了解.NET CF嗎?

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