Java JIT與AOT效能比較 - foojay

banq發表於2022-11-13

Java程式碼在執行時被編譯Just-In-Time (JIT) 與執行前被編譯Ahead-Of-Time (AOT) 區別是什麼?
為什麼與本機編譯的 AOT 應用程式相比,JIT 效能更好?
在這篇文章中,我對這兩種策略進行了快速更新,以闡明為什麼您會獲得不同的效能結果。

什麼是Just-In-Time(JIT)?
Java虛擬機器執行位元組碼,它是由你用Java(或其他支援的語言如Kotlin)編寫的程式碼生成的。這種位元組碼通常被打包成一個JAR檔案,執行時可以在任何平臺上執行。

在執行過程中,經常使用的方法(熱點)被識別並編譯成原生程式碼。這是用兩種編譯器完成的。C1(快速編譯,低最佳化)和C2(慢速編譯,高最佳化)。這種方法總是為應用程式執行的確切用例和平臺編譯出效能最好的原生程式碼。

這種方法的缺點是,在啟動時,虛擬機器在 "預熱時間 "內執行(慢的)位元組碼,直到它識別出熱點並達到完美的本地編譯程式碼。這個過程在每次啟動時都會重複。


什麼是Ahead-Of-Time(AOT)?
Java程式碼也可以被編譯成本地應用程式,例如使用GraalVM。在這種方法中,你的Java程式碼被靜態編譯,而編譯器則在特定平臺的可執行檔案中建立原生程式碼。

這樣做的好處是,在執行時不需要解釋位元組碼,不需要識別熱點,也不需要CPU負載進行編譯。因此,應用程式將在前面建立的本地編譯程式碼的基礎上全速啟動。

缺點是,你需要為所有你想執行應用程式的平臺進行編譯,而且執行時不包含原始程式碼,不能根據實際使用情況用它來進一步最佳化應用程式的行為。

不同的方法,不同的效能
如果所有的程式碼在執行前都被編譯了(AOT),那麼它的效能怎麼會比JIT編譯的程式碼差呢?
這就是JIT方法的真正優勢所在!

它可以根據實際需要調整編譯後的原生程式碼,以處理資料或執行其動作。

這些只是所謂的推測性最佳化的幾個例子:

  • 如果你的程式碼已經被建立為處理幾個if或switch案例,但其中有幾個選項從未被使用,它們將不會被編譯為原生程式碼,從而使程式碼更小更快。如果後來發現一些未編譯的選項是需要的,編譯器可以產生新的原生程式碼,以最佳方式處理該方法。
  • 在可能的情況下,編譯器會用一個公共變數代替私有變數,以減少對getter方法返回屬性值的需要。
  • 在Azul,我們已經看到,這種投機性的最佳化可以帶來高達50%的效能提升!


Ahead-Of-Time                  Just-In-Time
- 類載入防止方法內聯            + 可以使用積極的方法內聯
- 沒有執行時位元組碼生成           + 可以使用執行時位元組碼生成
- 反射很複雜                  + 反射很(相對)簡單
- 不能使用投機性最佳化             + 可以使用投機性最佳化
- 總體效能通常會更低             +總體效能通常會更高
+ 一開始就全速執行               - 需要預熱時間
+ 在執行時編譯程式碼沒有CPU開銷       - 在執行時編譯程式碼有CPU開銷



總結
AOT和JIT都提供了執行Java程式碼的好方法。但是,儘管AOT在啟動方面提供了一系列的優勢,但為了在執行期間獲得最佳效能的程式碼,JIT編譯器的影響也不應被低估。
 

相關文章