天天看點

Java是如何實作高性能的?

今天,從歐洲到澳洲,乘坐澳航的直達航班大約需要16個小時--這在100年前需要一個多月的旅程。如今,速度就是一切,這一原則也适用于軟體開發。在動态的本地和網絡應用的存在下,沒有使用者會等待内容的加載。這給軟體開發者帶來了真正的挑戰。那麼,在開發高性能軟體時,為什麼要從幾十種流行的選擇中選擇Java程式設計語言?在今天的文章中,我們将嘗試回答這個問題。我們将重點讨論使Java成為低延遲和高吞吐量系統的完美選擇的各個方面。

内容

  • Java虛拟機--Java性能的基礎
  • 是什麼使Java成為高性能系統的完美語言
  1. 編譯和解釋
  2. 平台獨立
  3. JIT - 即時編譯器
  4. 多線程能力
  5. 垃圾收集

Java虛拟機--Java性能的基礎

Java性能的核心是Java虛拟機,簡稱JVM。

JVM有兩個主要功能:允許Java程式在任何作業系統或裝置上運作(根據著名的 "寫一次,在任何地方運作 "原則),并優化和主動管理程式記憶體。

Java是如何實作高性能的?

  我們可以區分JVM的兩個定義。

1. Java虛拟機是軟體程式執行其代碼的運作環境。

2. Java虛拟機是Java程式的運作方式。我們配置好設定,然後在執行過程中依靠JVM來管理程式資源。

JVM中有很多元素,每一個元素都對軟體的性能有着深刻的影響。我們可以區分出對性能有影響的JVM的三個不同元件,開發人員可以對它們進行調整。

類加載器--當編譯一個.java源檔案時,它以.class檔案的形式被轉換為位元組碼。當你想在你的程式中使用這個類檔案時,它必須由類加載器加載到主程式記憶體中。這個過程包括3個階段,加載、連結和初始化,所有這些都對應用程式的性能有深刻的影響。

運作時記憶體/資料區 - 由5個核心部分組成,它負責提供記憶體來存儲位元組碼、參數、對象、傳回值和局部變量。

執行引擎 - 它負責執行每個類中存在的代碼。然而,在執行程式之前,位元組碼本身需要被轉換為JVM能夠了解的指令。為了實作這一點,JVM可以使用解釋器或JIT編譯器,我們将在下面詳細介紹。

Java是如何實作高性能的?

  JVM是實作真正的Java性能的一個關鍵工具。有經驗的開發者可以通過調整Java虛拟機的預設參數來微調它,以更好地滿足應用程式的需求。這個過程可以包括調整堆的大小,并選擇合适的垃圾收集器。

作為一般的經驗法則,在調整JVM時,你應該首先關注記憶體使用要求,然後是延遲,最後是應用程式的吞吐量。

是什麼讓Java成為高性能系統的完美語言

好了,我們已經确定JVM是實作Java性能的一個關鍵工具。那麼,使Java成為建構高性能軟體應用程式的完美程式設計語言的其他方面、特點和功能呢?

這裡有五個關鍵點。

1.編譯和解釋

程式設計語言通常可以是編譯的(C、C++、Haskell、Erlang或Rust)或解釋的(PHP、Python、Ruby和JavaScript)。

在這方面,Java是一種萬能的語言,因為它結合了編譯語言的力量和解釋語言的顯著靈活性。

正如我們之前在介紹Java虛拟機時提到的,Java編譯器(javac)将java源代碼編譯成位元組碼,然後可以在所有裝有JVM的機器上執行。

這張圖更好地展示了這個過程。

Java是如何實作高性能的?

2.平台的獨立性

JVM賦予了Java最大的優勢--平台獨立性。

Java虛拟機幾乎可以安裝在所有可用的作業系統上,從Windows,到Mac和Linux。平台獨立性允許在任何機器上編譯和執行代碼,并確定結果相同。

在這種情況下,位元組碼是實作完全平台獨立性的關鍵,也值得解釋一下位元組碼到底是什麼,因為我們在本文中已經提到過幾次。

Java位元組碼隻是一個包含JVM指令的程式。它的工作原理類似于彙編器,是C++代碼的一種表示。就其本身而言,它是一種二進制格式的代碼,由常量、引用和數字代碼組成,可由機器的硬體讀取和執行。

這裡有一張圖,解釋了Java位元組碼是如何實作平台獨立的。

Java是如何實作高性能的?

3.JIT - 及時編譯器

說到編譯,這裡是Java的另一張王牌--即時編譯器(JIT)編譯器)。将位元組碼轉換為本地機器語言執行的方式對它的速度有很大影響。JIT編譯器與Java虛拟機(JVM)互動,将Java位元組碼序列變成本地機器代碼。

重要的是,JIT編譯器是按需編譯代碼的。這意味着,它隻編譯正在被調用的方法。這大大提高了整體效率,節省了時間。

在使用JIT編譯器時,計算機硬體能夠直接執行本地代碼,而不是讓JVM一次又一次地解釋同一序列的位元組碼。如果編譯後的方法被頻繁地執行,這可能會導緻大量的性能提升。

更重要的是,JIT編譯器在編譯為本地機器語言的同時,還能進行很多簡單的優化。其中一些優化包括資料分析、從堆棧操作到寄存器操作的轉換、通過寄存器配置設定減少記憶體通路,以及消除常見的子表達式。

4.多線程能力

Java是一種能夠在語言層面上實作多線程的技術。多線程允許程式在多個計算核心和線程上執行并發的計算。更重要的是,多線程應用程式可以保持對輸入的響應,即使是在執行長期運作的任務時。

多線程現在比以往任何時候都更重要,特别是當硬體公司正在釋出越來越強大的企業級CPU,如新披露的Zen 4 Epyc處理器,提供令人震驚的192個計算線程。

區分多線程和多處理也很關鍵。第一個術語指的是在多個CPU線程上并發執行計算的能力。另一方面,後者指的是一個系統同時運作多個處理器的能力,其中每個處理器可以操作多個線程。

一般來說,多線程是首選,因為CPU線程使用一個共享的記憶體區域,這有助于節省記憶體,并允許稍快的内容切換。

5.垃圾收集

最後但并非最不重要的是,我們必須涵蓋Java的垃圾收集。簡而言之,它是Java程式進行自動記憶體管理的過程。當Java程式在JVM上運作時,對象在堆上被建立,但最終,其中一些對象将不再被需要。

垃圾收集器會自動檢測這些未使用的對象并将其删除,在此過程中釋放出寶貴的記憶體資源。

在Java中執行垃圾收集過程有三個階段。

  • 檢查是否符合條件

如果一個對象無法到達,就有資格進行垃圾收集(GC)。我們可以區分四種使Java對象符合垃圾收集條件的主要方式。

重新配置設定指針變量

Employee employeeOne = new Employee();

Employee employeeTwo = new Employee();

employeeOne = employeeTwo; // the first object referred by employeeOne is available for garbage collection

删除指針變量

Employee employee = new Employee();

employee = null;

使用匿名對象

register(new Employee());

隔離島(一組互相引用的對象,但不被應用程式中的任何活動對象所引用)。

  • 請求JVM運作垃圾收集器

請求JVM運作垃圾收集器可以通過兩種主要方式設定。

  • 使用System.gc()方法 - System類包含靜态方法gc(),用于請求JVM運作垃圾收集器。
  • 使用Runtime.getRuntime().gc()方法--Runtime類允許應用程式與運作該應用程式的JVM接口。通過使用其gc()方法,我們可以請求JVM運作GC。
  • 最終化

在删除一個對象之前,垃圾收集器對該對象使用finalize()方法來執行最後的清理活動。一旦finalize()方法完成,Garbage Collector就會删除該對象。

Java是如何實作高性能的 - 總結

Java實作了高性能的軟體開發,這是其他程式設計語言無法做到的。所有的開發人員都應該確定他們正在開發的Java程式能夠充分發揮其能力,并正确利用這種奇妙的程式設計語言所提供的所有工具。