簡介
現在的Java系統是一個全方位的開發、運行平台,可以在任何計算環境中實現,我們根據其運行平台的特點將其分為高端和低端兩種,高端是指所有非嵌入式系統的計算環境,SUN推出了J2SE和J2ME兩種版式。在低端即嵌入式系統,SUN推出了J2ME(Java 2 Platform Micro Edition)本文重點介紹J2ME。J2ME是SUN為了適應市場上日漸壯大的信息家電設備,如Mobile Phone,PDA等設備而推出的微型JAVA技術,主要用於開發電子產品,例如,行動電話、數字機頂盒、汽車導航系統等。
J2ME體系結構如圖 所示,其中profile,configuration和jvm是J2ME的組成部分。 J2ME是一個簡化的JAVA,並針對各種不同的底端設備而設計的,為了滿足各種環境J2ME設計了pro-file configuration規範。 configuration是一個語言特性和核心類的配置規範,針對不同的環境(記憶體、顯示、網路連線和處理能力)給定不同的配置。也就是定義了該環境的JAVA語言子集和核心類庫,虛擬機開發者遵照此配置來開發虛擬機,最著名的兩個配置是連線設備配置(CDC)和連結有限設備配置(CLDC)。另一方面, profile是針對相同的configuration的不同特性而開發的擴展類庫,它提供給開發者在特定類型設備上開發的類庫。如移動信息設備子集MIDP(Mobile Information De-vice Profile)就是綜合考慮了移動設備的螢幕和記憶體限制,定義了一些用戶接口,事件處理,存儲,網路等APIs。
根據具體的configuration,形成了具體的虛擬機需求,從而要求人們針對其進行相應的開發,如CDC因為其設備是較高端的,有豐富的資源,因此CDC使用了與J2SE一樣的JVM,而CLDC由於其設備資源受到限制,所以Sun專門開發了一個新的虛擬機KVM(K VirtualMachine)。當然,只要符合CLDC規範,我們也可以開發自己的虛擬機。如IBM開發的J9、visual-Age,微軟的MSJVM等,都符合JAVA虛擬機的規範,但還有各自不同的特點,具體內容請讀者參考相關資料。
機制
JAVA的基本原理
JAVA的目標和思想是“WRITE ONCE RUN ANYWHERE,”這是通過JAVA虛擬機機制來實現的。 JAVA虛擬機是一個純軟體的計算環境,建立在各種具體的硬體和作業系統上,實現了一個軟指令計算環境和垃圾回收管理記憶體,並在其上建立了類概念,編譯後的JAVA位元組碼可在其上運行。
Java以bytecode為中間碼,以對象為管理單位,以棧形式管理記憶體,使用翻譯的運行方式執行目標程式,圖是JAVA套用的運行流程。
程式開發平台
a) JAVA語言規範
嵌入式Java虛擬機的開發平台首先定義了一套語言規範,它是Java語言規範的子集。
1) Java語言規範使用上下文無關文法,以C和C++為基礎定義了自己的詞法結構、數據類型、數值和變數,其中,類型被細分為基本類型和擴展類型。基本類型在所有的機器上和所有的執行中被定義成一樣的。包括整型、單精度的浮點型、雙精度的浮點型、布爾型和Unicode字元型。擴展類型包括類類型、接口類型和數組類型。通過動態地創建類或數組的對象實例來實現擴展類型。數據類型支持類型轉換。
2) Java是面向對象的語言,以包的形式管理項目,以類為編譯單元。 Java類由域成員、方法成員和屬性成員組成,並包含異常處理,與C++不同, Java語言既不把聲明“ header”從類的實現中分開,也不把類型和類層次從類的實現中分開,並且把數組作為動態創建的對象,支持數組的數組,而不是多維數組。
3) Java語言規範定義了一個基本類型,基本類庫包含三個包: java. lang. java. io和java. util。其中java lang包定義了核心運行時類、核心數據類型類和幫助類: java. io包中則定義了輸入輸出類;而java. util包則定義了收集類和其它類(時間、日期和隨機數類等)。各個不同的嵌入式Java虛擬機在以上基本類庫的基礎上通過添加類來實現自己的特殊功能。
b)開發環境
對於現代的程式設計師,開發工具起著越來越重要的作用。使用嵌入式JAVA虛擬機進行程式開發,像開發PC機上的JAVA程式一樣,可以有很多種選擇。你可以直接使用文本編輯器寫程式,然後使用JDK進行編譯調試,也可以使用各種IDE進行編程,有很多種IDE可選,如Visual J++,Borland JBuilder、VisualAgeJava等。但與PC與JAVA程式所不同的是,我們要針對嵌入式系統安裝不同的是SDK,並使用不同的程式發布機制。另外,由於嵌入式系統的資源有限性,我們還需在發布之前完成程式的校驗工作。
c)類校驗
類校驗是JAVA虛擬機為了提高安全性而採用的一種方法,用於檢驗每個CLASS檔案是否都滿足必要的約束,並且也可以提高解釋期的性能。類校驗的基本內容有: 確認該檔案是不是具Java class檔案的基本格式。 進行一些附加檢驗,如:確認final類不被子類化, final方法不被覆蓋;確認每個類(除object)有一個超類等等。 對類中的每個方法進行檢驗,確認參數的合法性,局部變數訪問的合法性等問題。
d)程式的發布
應用程式編譯後運用打包工具,如使用專門的打包工具或者是IDE中包含的打包工具,或者由開發人員自己開發的打包工具,把預驗證後的類檔案、資源檔案、清單檔案打包,如果程式中還要用到其它類型的檔案,也需要添加到該包檔案中,然後就可以發布了。比如要發布JAVA程式,可以使用jar工具(來自J2SE)來打包,並且還需要編寫一描述檔案(JAD), JAD的要求同清單檔案一致。
運行平台
a)程式管理
JAVA程式是以類檔案或發布包的形式進行分發的,對PC系統而言,因為有檔案系統,管理是比較統一的,但對嵌入式系統而言,實現平台各異,不一定都有OS或檔案系統,因此,程式管理的實現將因系統而異,但其內容應基本一致,包括程式的安裝、查看、刪除和啟動等。
b)虛擬機的實現平台
目前嵌入式JAVA虛擬機的實現平台具有多種方式。它可以直接嵌入到裸機上,也可以載入於其他嵌入式作業系統之上,成為一台抽象的計算機。如它既可以運行在嵌入式linux平台上,也可以運行在windowsCE平台。它的平台無關性給它帶來了巨大的發展前景。更值得一提的是,目前sun公司已開發出了Java晶片,就其功能而言也不異於JAVA虛擬機,這種晶片可以說是Java虛擬機的硬體實現。
c)Class檔案格式
JVM對其實現的某些方面給出了具體的定義,特別是對Java可執行代碼,即位元組碼(Bytecode)的格式給出了明確的規格。這一規格包括操作碼和運算元的語法和數值、標識符的數值表示方式、以及Java類檔案中的Java對象、常量緩衝池在JVM的存儲映象。這些定義為JVM解釋器開發人員提供了所需的信息和開發環境。 Java的設計者希望給開發人員以隨心所欲使用Java的自由。下面介紹一下Class檔案格式:
我們在編寫JAVA程式時,編譯器將為每一個用戶定義的JAVA Class都成一個獨立的類檔案,因此我們把JAVA Class的構架名稱稱為ClassFile,CLASSFILE是一個有結構的位元組碼編譯後中間檔案,按類的結構進行組織,主要包括JAVA類檔案識別碼、版本號、常數池記錄長度、常數池、類訪問標誌、本類類名索引、超類索引、該類所實現的接口記錄長度、接口記錄表、該類的域成員數目、域成員組、該類的方法數目、方法表、該類的屬性數目、屬性組(屬性用於記錄類靜態成員變數的初始值或方法的代碼或方法的異常處理類型等具體內容)等。篇幅有限,這裡我們對ClassFile中各標記代表的具體內容不作介紹。
d)虛擬機的記憶體結構
JAVA虛擬機是一個面向對象的機器,所以,以類為核心結合執行緒機制進行管理。在整個系統中,通過類的載入機制完成從類檔案到運行時類實體結構的轉換,而在類實體結構中包含了該類所定義的各種實體的內容,包括類成員變數定義表、類方法定義、類的常數池(相當於符號表)以及該類的靜態成員變數表,這些內容構成了類定義的全部,而該類的實例表則是所有該類的實例對象的索引,類的實例對象的結構都是通過類的成員變數定義表來表達的,對象本身的定義只是一個byte數組及一個指向該類實體結構的索引。
當VM建立一個Java thread的同時,會在Java heap中一同建立起一個專屬於該thread的excution stack,而存儲在這個exe-cution stack中的是一種稱作frame結構的數據結構。 JavaVM為方法的每一次執行建立一個frame,在frame中存儲方法的局部變數和參數,並為該函式的執行建立一個局部的運算元棧,該方法函式的所有操作都針對該局部運算元棧。而不論該method是正常或不正常的結束執行時,VM都會把在execution stack中與之對應的frame給釋放掉。Java具備垃圾回收的記憶體管理機制,這主要是針對對象和數組對象來說的,對象和數組是在回收堆中進行分配的,當該對象無用時,系統將釋放對象回收該記憶體。虛擬機記憶體總體的結構圖如圖所示。
e)指令系統
Java虛擬機是一個虛擬的計算機,像其他計算機一樣有自己的暫存器和指令集。為了提高虛擬機指令的執行效率, JAVA VM只設定了4個最為常用的暫存器。它們是:
pc程式計數器;
optop運算元棧頂指針;
frame當前執行環境指針;
vars指向當前執行環境中第一個局部變數的指針。
所有暫存器均為32位。 pc用於記錄程式的執行。 optop,frame和vars用於記錄指向Java棧區的指針。JAVA VM指令系統同其他計算機的指令系統極其相似, Ja-va指令也是由操作碼和運算元兩部分組成。操作碼為8位二進制數, Java的8位操作碼的長度使得JVM最多有256種指令,目前已使用了160多種操作碼。運算元緊隨在操作碼的後面,其長度根據需要而不同。當長度大於8位時,運算元被分為兩個以上位元組存放。
JVM採用了“ big endian”的編碼方式來處理這種情況,即高位bits存放在低位元組中。JAVA虛擬機規範定義了許多指令,按功能可分以下類別:裝載和存儲指令、運算指令、類型轉換指令、對象創建和操縱、運算元棧管理指令、控制轉移指令、方法調用和返回指令、拋出和處理異常的指令、實現finally的指令、同步指令等。而指令的運算元則主要包括以下四種:
•當前方法的FRAME框架的局部變數的索引值;
•當前類的常數池的索引值,通過該索引值來定位運算元的具體位置;
•方法域的相對當前指令的偏移量(如控制轉移指令、異常等);
•運算元棧。
對於對象或數組變數,其值均指對象在堆記憶體中的指針,為引用變數,需要通過計算取得值,而對於其他變數,可看作是實數變數,包括運算元種的實體變數、當前框架的實體變數和指令中的運算元。
f)運行流程
運行JVM位元組碼的工作是由解釋器來完成的。解釋執行過程分三部進行:代碼的裝入、代碼的校驗和代碼的執行。裝入代碼的工作由“類裝載器”(class loader)完成。類裝載器負責裝入運行一個程式需要的所有代碼,這也包括程式代碼中的類所繼承的類和被其調用的類。當類裝載器裝入一個類時,該類被放在自己的名字空間中。除了通過符號引用自己名字空間以外的類,類之間沒有其他辦法可以影響其他類。在本台計算機上的所有類都在同一地址空間內,而所有從外部引進的類,都有一個自己獨立的名字空間。這使得本地類通過共享相同的名字空間獲得較高的運行效率,同時又保證它們與從外部引進的類不會相互影響。當裝入了運行程式需要的所有類後,解釋器便可確定整個可執行程式的記憶體布局。解釋器為符號引用同特定的地址空間建立對應關係及查詢表。通過在這一階段確定代碼的記憶體布局, Java很好地解決了由超類改變而使子類崩饋的問題,同時也防止了代碼對地址的非法訪問。隨後,被裝入的代碼由位元組碼校驗器進行檢查。校驗器可發現運算元棧溢出,非法數據類型轉化等多種錯誤。通過校驗後,代碼便開始執行了。