Java能不能像C語言不通過JVM虛擬機直接編譯成二進制機器碼,讓計算機直接運行?

小松語錄


一些處理器裡有JAVA協處理器,可以運行JAVA字節碼,幾乎相當於二進制支持了。

Jazelle DBX技術把Java字節碼分為3類:直接執行、模擬執行(emulated)和未定義。大多數Java字節碼(ARM926EJ-S支持134個)可由 硬件直接執行,餘下的由一些簡短的高度優化的ARM指令序列模擬執行。把原先虛擬機中的解釋器去掉,替換以ARM專有的代碼(稱為VMZ,這些代碼甚至比 替掉的代碼更小)。

統計分析表明,在一段典型的程序代碼中,需要模擬執行的字節碼不會超過5%。這就是為什麼ARM決定Jazelle DBX硬件擴展只支持直接執行部分的字節碼,而非全部。Jazelle DBX硬件擴展的實現約為一萬兩千門的規模,而大多數的專用Java處理器或協處理器通常有6萬到10萬門的規模。這樣的設計策略把硬件邏輯的複雜度減到 最小、功耗低、系統集成難度低,卻仍能表現出很高的整體Java性能。



味冷


從語言設計的角度看是可以的,重新設計一下編譯器就能實現,但從工程實踐的角度看是不可行的。

其一,Java語言最大的特點就是跨平臺可移植,一次開發,一次編譯,多平臺執行,這一特性就是靠JVM(Java虛擬機)實現的,如果改寫編譯器像C語言一樣直接編譯成了可執行程序,就失去了跨平臺特性。

其二,Java語言設計之初就設計成為了一款嚴重依賴JRE(Java運行時環境)的語言,有部分語言設計上的缺陷必須依賴JVM來解決,比如GC(垃圾回收),我們知道,Java語言是沒有內存回收能力的,因此還得靠JVM,在工程實踐中,如果軟件不能進行內存回收,後果將是災難性的。

其三,Java語言是面向對象的,區別於同是面向對象的C++,Java還有一個動態特性。

它允許程序動態地裝入運行過程中所需要的類,這是C++語言進行面向對象程序設計所無法實現的。在C++程序設計過程中,每當在類中增加一個實例變量或一種成員函數後,引用該類的所有子類都必須重新編譯,否則將導致程序崩潰。Java從如下幾方面採取措來解決這個問題。Java編譯器不是將對實例變量和成員函數的引用編譯為數值引用,而是將符號引用信息在字節碼中保存下傳遞給解釋器,再由解釋器在完成動態連接類後,將符號引用信息轉換為數值偏移量。這樣,一個在存儲器生成的對象不在編譯過程中決定,而是延遲到運行時由解釋器確定的。這樣,對類中的變量和方法進行更新時就不至於影響現存的代碼。解釋執行字節碼時,這種符號信息的查找和轉換過程僅在一個新的名字出現時才進行一次,隨後代碼便可以全速執行。在運行時確定引用的好處是可以使用已被更新的類,而不必擔心會影響原有的代碼。如果程序連接了網絡中另一系統中的某一類,該類的所有者也可以自由地對該類進行更新,而不會使任何引用該類的程序崩潰。而這一切同樣依賴JRE。

以上幾點決定了Java不能像C語言一樣直接編譯成機器碼,當然,還有一些其它因素,但我認為上面幾點是最主要的。


ScienceTech365


C語言的編譯過程如下:

C源程序-->預編譯處理(.c)-->編譯、優化程序(.s、.asm)-->彙編程序(.obj、.o、.a、.ko)-->鏈接程序(.exe、.elf、.axf等),如圖1所示。其實編譯裡面還包括詞法分析、語法分析、語義分析,就不展開說了。

而Java的執行可以分為兩大步驟,如圖2所示,第一是編譯,這一過程就是調用的javac命令,編譯成對應的.class文件。第二是解釋執行,這一過程是調用的java命令,其實我理解的是調用了Java裡的jvm,即java虛擬機。JVM其實計算機把高級語言解析成機器碼都會存在一個類似這樣的中間件。在c#中,我知道先編譯成CIL託管代碼,然後Jit編譯器在CLR(公共語言運行時)這樣一個庫下把託管代碼解釋成可執行文件.exe或者dll。現在我就把JVM看作是JIT編譯器。把要執行的代碼翻譯給計算機聽,然後機器執行,大致也就是這麼個道理。當然了Java程序還是通過解釋器進行解釋執行時,當JVM發現某個方法或代碼塊運行特別頻繁的時候,就會認為這是“熱點代碼”(Hot Spot Code)。然後JIT會把部分“熱點代碼”翻譯成本地機器相關的機器碼,並進行優化,然後再把翻譯後的機器碼緩存起來,以備下次使用。總的來說還是需要JVM。

如果你想把Java編譯成二進制機器碼,那要重新開發一個編譯器,將Java源代碼通過編譯(包括詞法分析、語法分析、語義分析,中間代碼,優化等)生成彙編語言,然後再轉化成機器碼。這樣以來,每個平臺(X86,ARM,MIPS,PowerPC等)都需要重新編譯生成相應平臺的機器碼,而且如果沒有JVM,就沒有GC(垃圾自動回收)功能了。




分享到:


相關文章: