您好,登錄后才能下訂單哦!
這篇文章主要介紹“Java和C++的性能比較”,在日常操作中,相信很多人在Java和C++的性能比較問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java和C++的性能比較”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
1. 概述
編程語言根據(jù)其抽象級別進行分類。我們區(qū)分高級語言(Java,Python,JavaScript,C ++,Go),低級語言(匯編程序),最后是機器代碼。
每個高級語言代碼(例如Java)都需要轉(zhuǎn)換為機器本地代碼才能執(zhí)行。該翻譯過程可以是編譯或解釋。但是,還有第三種選擇。試圖利用兩種方法的組合。
2. 編譯與解釋
讓我們開始研究編譯和解釋語言之間的一些差異。
2.1 編譯語言
編譯器將編譯語言(C ++,Go)直接轉(zhuǎn)換為機器碼。
在執(zhí)行之前,它們需要明確的構(gòu)建步驟。這就是為什么每次更改代碼時都需要重新編譯程序。
編譯語言往往比解釋語言更快,更有效。但是,它們生成的機器碼是特定于平臺的。
2.2 解釋語言
在解釋語言(Python,JavaScript)中,沒有構(gòu)建步驟。相反,解釋器在執(zhí)行程序時對程序的源代碼進行操作。
曾經(jīng)認為解釋語言比編譯語言要慢得多。但是,隨著即時編譯(JIT)的發(fā)展,性能差距正在縮小。JIT編譯器在程序運行時將代碼從解釋語言轉(zhuǎn)換為機器碼。
此外,我們可以在Windows,Linux或Mac等多個平臺上執(zhí)行解釋后的語言代碼。解釋代碼與特定類型的CPU體系結(jié)構(gòu)沒有關(guān)聯(lián)。
3. Write Once Run Anywhere
Java和JVM在設(shè)計時考慮了可移植性。因此,當今大多數(shù)流行的平臺都可以運行Java代碼。
這聽起來似乎暗示著Java是一種純解釋性語言。但是,在執(zhí)行之前,需要將Java源代碼編譯為字節(jié)碼。字節(jié)碼是JVM固有的一種特殊機器語言。JVM在運行時解釋并執(zhí)行此代碼。
它是JVM為支持Java的每個平臺構(gòu)建和定制的,并不是我們的程序或庫。
JVM也具有JIT編譯器。這意味著JVM在運行時優(yōu)化我們的代碼,以獲得與編譯語言相似的性能優(yōu)勢。
4. Java編譯器
javac的命令行工具把Java源代碼編譯轉(zhuǎn)換成Java類文件(xxx.class)與平臺無關(guān)的字節(jié)碼:
$ javac HelloWorld.java
源代碼文件帶有.java后綴,而包含字節(jié)碼的類文件則帶有.class后綴。
5. Java虛擬機
編譯的類文件(字節(jié)碼),可以由JVM執(zhí)行:
$ java HelloWorld Hello Java!
在運行時如何將字節(jié)碼轉(zhuǎn)換為機器本機代碼。
5.1 架構(gòu)概述
JVM由五部分組成:
類加載器
JVM內(nèi)存結(jié)構(gòu)
執(zhí)行引擎
本地方法接口
本地方法庫
5.2 類加載器
JVM利用ClassLoader將已編譯的類文件加載到JVM內(nèi)存
除加載外,ClassLoader還執(zhí)行鏈接和初始化。
驗證字節(jié)碼是否存在安全漏洞
為靜態(tài)變量分配內(nèi)存
用原始引用替換符號內(nèi)存引用
將原始值分配給靜態(tài)變量
執(zhí)行所有靜態(tài)代碼塊
5.3 執(zhí)行引擎
執(zhí)行引擎負責讀取字節(jié)碼,將其轉(zhuǎn)換為機器本機代碼并執(zhí)行。
三個主要組件負責執(zhí)行,包括解釋器和編譯器:
由于JVM與平臺無關(guān),因此它使用解釋器執(zhí)行字節(jié)碼
JIT編譯器在重復的方法調(diào)用處,把字節(jié)碼編譯為本地代碼以提高性能。
垃圾收集器收集并刪除所有未引用的對象。
執(zhí)行引擎利用本機方法接口(JNI)來調(diào)用本地庫和應用程序。
5.4 即時編譯器(JIT)
解釋器的主要缺點是:每次調(diào)用方法時,都需要解釋執(zhí)行,這比編譯的本機代碼要慢。Java使用JIT編譯器來克服此問題。
JIT編譯器不能完全替代解釋器。執(zhí)行引擎仍在使用它。但是,JVM根據(jù)調(diào)用方法的頻率使用JIT編譯器。
JIT編譯器將整個方法的字節(jié)碼編譯為機器本機代碼,因此可以直接重用。與標準編譯器一樣,生成中間代碼,進行優(yōu)化,然后生成機器本機代碼。
探查器是JIT編譯器的特殊組件,負責查找熱點。JVM根據(jù)運行時收集的性能分析信息來決定要編譯的代碼。
這樣的效果是,經(jīng)過幾個執(zhí)行周期,Java程序可以更快地執(zhí)行其工作。JVM了解到熱點后,便可以創(chuàng)建本機代碼,從而使運行速度更快。
6. 性能比較
讓我們看一下JIT編譯如何提高Java的運行時性能。
6.1 斐波那契數(shù)列性能測試
我們將使用一種簡單的遞歸方法來計算第n個斐波那契數(shù):
private static int fibonacci(int index) { if (index <= 1) { return index; } return fibonacci(index-1) + fibonacci(index-2); }
為了衡量重復方法調(diào)用的性能收益,我們將運行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); }
首先,我們將正常編譯并執(zhí)行Java代碼:
$ java Fibonacci.java
然后,我們將在禁用JIT編譯器的情況下執(zhí)行相同的代碼:
$ java -Djava.compiler=NONE Fibonacci.java
最后,我們將在C ++和JavaScript中實現(xiàn)并運行相同的算法進行比較。
6.2 性能測試結(jié)果
讓我們看一下運行斐波那契數(shù)列測試后以納秒為單位測量的平均性能:
使用JIT編譯器的Java – 2726 ns –最快
沒有JIT編譯器的Java – 17965 ns –慢559%
沒有O2優(yōu)化的C ++ – 9435 ns –降低246%
具有O2優(yōu)化的C ++ – 3639 ns –慢33%
JavaScript – 22998 ns –慢743%
在此示例中,使用JIT編譯器,Java的性能提高了500%以上。但是,JIT編譯器確實需要運行一些才能運行。
有趣的是,即使在啟用O2優(yōu)化標志的情況下編譯C ++,Java的性能也比C ++代碼好33%。當仍在解釋Java時,C ++在前幾次運行中的性能要好得多。
Java還勝過與Node一起運行的等效JavaScript代碼,后者也使用JIT編譯器。結(jié)果顯示性能提高了700%以上。主要原因是Java的JIT編譯器啟動速度更快。
7. 思考
從技術(shù)上講,可以將任何靜態(tài)編程語言代碼直接編譯為機器代碼。也可以逐步解釋任何編程代碼。
與許多其他現(xiàn)代編程語言類似,Java使用編譯器和解釋器的組合。目標是利用兩全其美,實現(xiàn)高性能和平臺無關(guān)的執(zhí)行。
在本文中,我們重點介紹了HotSpot中的工作方式。HotSpot是Oracle默認的開源JVM實現(xiàn)。Graal VM也基于HotSpot,因此適用相同的原理。
如今,最流行的JVM實現(xiàn)使用解釋器和JIT編譯器的組合。但是,其中一些也可能使用其他方式。
8. 結(jié)論
Java使用了兩種方法的組合。
我們用Java編寫的源代碼在構(gòu)建過程中首先被編譯為字節(jié)碼。然后,JVM解釋生成的字節(jié)碼以供執(zhí)行。但是,JVM還在運行時使用JIT編譯器來提高性能。
到此,關(guān)于“Java和C++的性能比較”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。