Java是編譯語言還是解釋語言?

    1.概述

    編程語言根據其抽象級別進行分類。我們區分高級語言(Java,Python,JavaScript,C ++,Go),低級語言(彙編程序),最後是機器代碼。

    每個高級語言代碼(例如Java)都需要轉換為機器本地代碼才能執行。該翻譯過程可以是編譯或解釋。但是,還有第三種選擇。試圖利用兩種方法的組合。

    在本教程中,我們將探討如何在多個平台上編譯和執行Java代碼。我們將研究一些Java和JVM設計細節。這些將幫助我們確定Java是編譯,解釋還是兩者的混合。

    2.編譯與解釋

    讓我們開始研究編譯和解釋編程語言之間的一些基本差異。

    2.1。編譯語言

    編譯器將編譯語言(C ++,Go)直接轉換為機器本機代碼。

    在執行之前,它們需要明確的構建步驟。這就是為什麼每次更改代碼時都需要重建程序。

    編譯語言往往比解釋語言更快,更有效**。**但是,它們生成的機器代碼是特定於平台的。

    2.2。解釋型語言

    另一方面,在解釋語言(Python,JavaScript)中,沒有構建步驟。相反,解釋器在執行程序時對程序的源代碼進行操作。

    曾經認為口譯語言比編譯語言要慢得多。但是,隨著即時(JIT)編譯的發展,性能差距正在縮小。但是,我們應該注意,JIT編譯器在程序運行時將代碼從解釋語言轉換為機器本地代碼。

    此外,我們可以Windows,Linux或Mac等多個平台上執行解釋後的語言代碼。解釋的代碼與特定類型的CPU體系結構沒有關聯。

    3.寫一次即可在任何地方運行

    Java和JVM在設計時考慮了可移植性。因此,當今大多數流行的平台都可以運行Java代碼。

    這聽起來似乎暗示著Java是一種純解釋性語言。但是,在執行之前,需要將Java源代碼編譯為字節碼。字節碼是JVM固有的一種特殊機器語言. JVM在運行時解釋並執行此代碼。

    是為支持Java的每個平台(而不是我們的程序或庫)構建和定制的JVM。

    現代JVM也具有JIT編譯器。這意味著JVM在運行時優化我們的代碼,以獲得與編譯語言相似的性能優勢。

    4. Java編譯器

    javac命令行工具將Java源代碼編譯成包含平台無關字節碼的Java類文件

    $ javac HelloWorld.java

    源代碼文件帶有.java後綴,而包含字節碼的類文件則由生成。 class後綴。

    Java是編譯語言還是解釋語言?

    5. Java虛擬機

    編譯的類文件(字節碼)可以由Java虛擬機(JVM)執行:

    $ java HelloWorld Hello Java!

    現在讓我們更深入地研究JVM體系結構。我們的目標是確定在運行時如何將字節碼轉換為機器本機代碼。

    5.1。架構概述

    JVM由五個子系統組成:

    • 類加載器
    • JVM內存
    • 執行引擎
    • 本機方法接口和
    • 本機方法庫

    Java是編譯語言還是解釋語言?

    5.2。類加載器

    JVM利用ClassLoader子系統將已編譯的類文件帶入**JVM內存**。

    除加載外,ClassLoader還執行鏈接和初始化。那包括:

    • 驗證字節碼是否存在安全漏洞
    • 為靜態變量分配內存
    • 用原始引用替換符號內存引用
    • 將原始值分配給靜態變量
    • 執行所有靜態代碼塊

    5.3。執行引擎

    執行引擎子系統負責讀取字節碼,將其轉換為機器本機代碼並執行。

    三個主要組件負責執行,包括解釋器和編譯器:

    • 由於JVM與平台無關,因此它使用解釋器執行字節碼
    • JIT編譯器通過將字節碼編譯為本地代碼以重複方法調用來提高性能
    • 垃圾收集器收集並刪除所有未引用的對象

    執行引擎利用本機方法接口(JNI)來調用本機庫和應用程序。

    5.4。即時編譯器

    解釋器的主要缺點是,每次調用方法時,都需要解釋,這可能比編譯的本機代碼慢。 Java使用JIT編譯器來克服此問題。

    JIT編譯器不能完全替代解釋器。執行引擎仍在使用它。但是,JVM根據調用方法的頻率使用JIT編譯器。

    JIT編譯器將整個方法的字節碼編譯為機器本機代碼,因此可以直接重用與標準編譯器一樣,生成中間代碼,進行優化,然後生成機器本機代碼。

    探查器是JIT編譯器的特殊組件,負責查找熱點。 JVM根據運行時收集的性能分析信息來決定要編譯的代碼。

    Java是編譯語言還是解釋語言?

    這樣的效果是,經過幾個執行週期,Java程序可以更快地執行其工作。 JVM了解到熱點後,便可以創建本機代碼,從而使運行速度更快。

    6.性能比較

    讓我們看一下JIT編譯如何提高Java的運行時性能。

    6.1。斐波那契性能測試

    我們將使用一種簡單的遞歸方法來計算第n個斐波那契數:

    private static int fibonacci(int index) {
    
     if (index <= 1) {
    
     return index;
    
     }
    
     return fibonacci(index-1) + fibonacci(index-2);
    
     }

    為了衡量重複方法調用的性能收益,我們將運行Fibonacci方法100次:

    for (int i = 0; i < 100; i++) {
    
     long startTime = System.nanoTime();
    
     int result = fibonacci(12);
    
     long totalTime = System.nanoTime() - startTime;
    
     System.out.println(totalTime);
    
     }

    首先,我們將正常編譯並執行Java代碼:

    $ java Fibonacci.java

    然後,我們將在禁用JIT編譯器的情況下執行相同的代碼:

    $ java -Djava.compiler=NONE Fibonacci.java

    最後,我們將在C ++和JavaScript中實現並運行相同的算法進行比較。

    6.2。性能測試結果

    讓我們看一下運行Fibonacci遞歸測試後測得的平均性能(以納秒為單位):

    • 使用JIT編譯器的Java – 2726 ns –最快
    • 沒有JIT編譯器的Java – 17965 ns –慢559%
    • 沒有O2優化的C ++ – 9435 ns –降低246%
    • 具有O2優化的C ++ – 3639 ns –慢33%
    • JavaScript – 22998 ns –慢743%

    在此示例中,使用JIT編譯器Java的性能提高了500%以上。但是,JIT編譯器確實需要運行一些才能運行。

    有趣的是,即使在啟用O2優化標誌的情況下編譯C ++,Java的性能也比C ++代碼好33%。不出所料,當仍然解釋Java時, C ++在前幾次運行中的性能要好得多

    Java還勝過與Node一起運行的等效JavaScript代碼,後者也使用JIT編譯器。結果顯示性能提高了700%以上。主要原因是Java的JIT編譯器啟動速度更快

    7.要考慮的事情

    從技術上講,可以將任何靜態編程語言代碼直接編譯為機器代碼。也可以逐步解釋任何編程代碼。

    與許多其他現代編程語言類似,Java使用編譯器和解釋器的組合。目標是利用兩全其美,實現高性能和平台無關的執行

    在本文中,我們重點介紹了HotSpot中的工作方式。 HotSpot是Oracle默認的開源JVM實現。 Graal VM也基於HotSpot,因此適用相同的原理。

    如今,最流行的JVM實現使用解釋器和JIT編譯器組合。但是,其中一些可能使用其他方法。

    8.結論

    在本文中,我們研究了Java和JVM內部。我們的目標是確定Java是編譯語言還是解釋語言。我們探索了Java編譯器和JVM執行引擎的內部結構。

    基於此,我們得出結論, Java使用了兩種方法的組合。

    我們用Java編寫的源代碼在構建過程中首先被編譯為字節碼。然後,JVM解釋生成的字節碼以供執行。但是,JVM還在運行時使用JIT編譯器來提高性能。