Java - From Compilation To Execution


想像一下,如果你的team正在決定一項可跨平台的功能或系統應該由什麼程式語言編寫時,你應該如何說服你的teammates使用Java呢? 你該如何說明為什麼中間有個JVM就可以跨平台?
或是當Java的擁護者們正熱情的告訴你Java可以跨平台,一次編寫到處執行;跟C/C++效能接近,而且你根本不需要操作麻煩的Pointer跟Memory。但是你知道為什麼嗎?

今天來簡單描述一下Java程式背後的編譯及執行的過程。

雖然這篇的內容通常被各大網站標注為Easy, Basic, Java入門基礎,但對於一個初入程式或稍微有程式基礎的Java新手而言絕不可能是簡單的。也許新手可以理解詞意文義,但根本無法想像這些東西究竟用在什麼地方,最後只能先背下來。而一般Java開發上也很少特別去在意這些過程。
因此本篇適合已經有Java程式開發經驗的讀者,對於Java的優缺點、程式語言之間的比較、判斷Java適合用在什麼地方等,這些基礎觀念就顯得重要了。

基本上Java會先將 *.java 原始碼編譯為 java bytecode 並將他們存在 *.class 檔。 然後JVM(Java Virtual Machine)載入main class程式碼(也就是有宣告main進入點的編譯後檔案)至記憶體內執行,接著依序載入被參考的class來執行整個Java程序。

編譯 Compilation

  1. Parsing Source Code
    首先編譯器會讀取指定的 *.java 原始碼檔案,並將其產生的token sequence映射到 AST(Abstract Syntax Tree)上。

  2. Registering Symbols Into Symbol Table
    接下來編譯器會將定義的symbols註冊至symbol table

  3. Processing Annotations
    如果程式中有annotation的話會在這時候處理。注意:處理annotations是在compile time而不是runtime。這裡有一個很好的文章講述如何實作Annotations Processing

  4. Attributes AST
    這時編譯器會整理AST,包括 name resolution, type checking, 以及 constants folding

  5. Dataflow Analysis
    整理完AST後會進行dataflow analysis,主要是檢查變數assignments以及是否reachable。

  6. Desugar
    Java程式語言中提供 語法糖(Syntactic sugar) 方便使用者編寫程式,而在編譯階段會將這些語法糖轉譯掉,變回標準的形式。

  7. Generate Class Files
    上面流程全都順利進行的話,compiler會產生bytecode,也就是 *.class 檔的內容。

執行 Execution

JVM首先載入main class的bytecode到memory中執行,再經過三個主要的程序,最後才執行整個程式。

Stage 1: Class Loader

main class首先被JVM載入執行,而後所有被main class參考的class都會透過class loader被載入執行。
class loader主要分為兩種:primordialnon-primordial
primordial class loader是JVM系統內建的,作為預設的class loader。non-primordial class loader則是使用者自定義的,如果有被定義則優先於預設的class loader。

Stage 2: Bytecode Verifier

在class被class loader載入後,bytecode verifier會檢查程式,以避免程式中的指令具有破壞性的操作。
主要檢查以下幾點:

  • 變數在被使用前須先初始化
  • Method的調用符合參考物件的類型
  • 不違反 private members(methods & variables)的調用規則
  • 存取的局部變數(local variables)須屬於runtime stack中
  • runtime stack does not overflow

如果上述任一點檢查失敗,則不會允許class被載入。

Stage 3: Just-In-Time Compiler (JIT)

這是JVM最後的執行階段,透過JIT可以將bytecode轉為native machine code,而不是讓JVM不斷重複的去解譯那些bytecode造成冗長的編譯過程,這可以使程式執行的效率提高。

結論 Conclusion

經過上方的說明,我們可以知道即使在不同平台,只要平台上安裝Java runtime,也就是有JVM的存在時,我們就可以將.class檔拿給JVM執行,實現跨平台的功能。但這也是Java的限制之一,因為作業系統上需要有Java runtime的存在才能執行Java,因此現在Java多數用於網站後端服務。

參考資料


Read other notes

Tags

Notes mentioning this note

There are no notes linking to this note.

Notes Graph