今天,從歐洲到澳洲,乘坐澳航的直達航班大約需要16個小時--這在100年前需要一個多月的旅程。如今,速度就是一切,這一原則也适用于軟體開發。在動态的本地和網絡應用的存在下,沒有使用者會等待内容的加載。這給軟體開發者帶來了真正的挑戰。那麼,在開發高性能軟體時,為什麼要從幾十種流行的選擇中選擇Java程式設計語言?在今天的文章中,我們将嘗試回答這個問題。我們将重點讨論使Java成為低延遲和高吞吐量系統的完美選擇的各個方面。
内容
- Java虛拟機--Java性能的基礎
- 是什麼使Java成為高性能系統的完美語言
- 編譯和解釋
- 平台獨立
- JIT - 即時編譯器
- 多線程能力
- 垃圾收集
Java虛拟機--Java性能的基礎
Java性能的核心是Java虛拟機,簡稱JVM。
JVM有兩個主要功能:允許Java程式在任何作業系統或裝置上運作(根據著名的 "寫一次,在任何地方運作 "原則),并優化和主動管理程式記憶體。
我們可以區分JVM的兩個定義。
1. Java虛拟機是軟體程式執行其代碼的運作環境。
2. Java虛拟機是Java程式的運作方式。我們配置好設定,然後在執行過程中依靠JVM來管理程式資源。
JVM中有很多元素,每一個元素都對軟體的性能有着深刻的影響。我們可以區分出對性能有影響的JVM的三個不同元件,開發人員可以對它們進行調整。
類加載器--當編譯一個.java源檔案時,它以.class檔案的形式被轉換為位元組碼。當你想在你的程式中使用這個類檔案時,它必須由類加載器加載到主程式記憶體中。這個過程包括3個階段,加載、連結和初始化,所有這些都對應用程式的性能有深刻的影響。
運作時記憶體/資料區 - 由5個核心部分組成,它負責提供記憶體來存儲位元組碼、參數、對象、傳回值和局部變量。
執行引擎 - 它負責執行每個類中存在的代碼。然而,在執行程式之前,位元組碼本身需要被轉換為JVM能夠了解的指令。為了實作這一點,JVM可以使用解釋器或JIT編譯器,我們将在下面詳細介紹。
JVM是實作真正的Java性能的一個關鍵工具。有經驗的開發者可以通過調整Java虛拟機的預設參數來微調它,以更好地滿足應用程式的需求。這個過程可以包括調整堆的大小,并選擇合适的垃圾收集器。
作為一般的經驗法則,在調整JVM時,你應該首先關注記憶體使用要求,然後是延遲,最後是應用程式的吞吐量。
是什麼讓Java成為高性能系統的完美語言
好了,我們已經确定JVM是實作Java性能的一個關鍵工具。那麼,使Java成為建構高性能軟體應用程式的完美程式設計語言的其他方面、特點和功能呢?
這裡有五個關鍵點。
1.編譯和解釋
程式設計語言通常可以是編譯的(C、C++、Haskell、Erlang或Rust)或解釋的(PHP、Python、Ruby和JavaScript)。
在這方面,Java是一種萬能的語言,因為它結合了編譯語言的力量和解釋語言的顯著靈活性。
正如我們之前在介紹Java虛拟機時提到的,Java編譯器(javac)将java源代碼編譯成位元組碼,然後可以在所有裝有JVM的機器上執行。
這張圖更好地展示了這個過程。
2.平台的獨立性
JVM賦予了Java最大的優勢--平台獨立性。
Java虛拟機幾乎可以安裝在所有可用的作業系統上,從Windows,到Mac和Linux。平台獨立性允許在任何機器上編譯和執行代碼,并確定結果相同。
在這種情況下,位元組碼是實作完全平台獨立性的關鍵,也值得解釋一下位元組碼到底是什麼,因為我們在本文中已經提到過幾次。
Java位元組碼隻是一個包含JVM指令的程式。它的工作原理類似于彙編器,是C++代碼的一種表示。就其本身而言,它是一種二進制格式的代碼,由常量、引用和數字代碼組成,可由機器的硬體讀取和執行。
這裡有一張圖,解釋了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程式能夠充分發揮其能力,并正确利用這種奇妙的程式設計語言所提供的所有工具。