C代码的运行速度总是比Java快,对吧? 错误!
因此,我們都知道,Java解釋緩慢且C的編譯和優(yōu)化運行速度非常快。 您可能知道,圖片截然不同。
TL; DR Java適用于星座,它的速度更快,在JIT上可以執(zhí)行內(nèi)聯(lián),因為所有方法/功能都是可見的,而C編譯器無法在編譯單元(例如庫等)上執(zhí)行優(yōu)化。
AC編譯器將C代碼作為輸入,對其進行編譯和優(yōu)化,并生成要執(zhí)行的特定CPU或體系結(jié)構(gòu)的機器代碼。 這導(dǎo)致可執(zhí)行文件,無需進一步步驟即可直接在給定計算機上運行。 另一方面,Java有一個中間步驟:字節(jié)碼。 因此,Java編譯器將Java代碼作為輸入并生成字節(jié)碼,而字節(jié)碼基本上是抽象機的機器代碼。 現(xiàn)在,對于每個(流行的)CPU架構(gòu),都有一個Java Virual機器,該機器模擬此抽象機器并執(zhí)行(解釋)生成的字節(jié)碼。 這聽起來很慢。 但是另一方面,字節(jié)碼是可移植的,因為相同的輸出將在所有平臺上運行,因此口號“ 一次寫入,隨處運行 ”。
現(xiàn)在,使用上述方法,它會變得“ 寫一次,到處等待 ”,因為解釋器會很慢。 因此,現(xiàn)代JVM要做的就是及時編譯。 這意味著JVM在內(nèi)部將字節(jié)碼轉(zhuǎn)換為用于CPU的機器代碼。 但是由于此過程非常復(fù)雜,因此Hotspot JVM (最常用的一種)僅對經(jīng)常執(zhí)行的代碼片段執(zhí)行此操作(因此命名為Hotspot )。 除了更快地啟動(解釋器立即啟動,JIT編譯器根據(jù)需要啟動)之外,還有另一個好處:熱點JIT已經(jīng)知道經(jīng)常調(diào)用什么部分,什么不經(jīng)常調(diào)用-因此它可以在優(yōu)化輸出時使用它–這就是我們的例子發(fā)揮作用的地方。
現(xiàn)在,在查看我的完整示例之前,請注意,Java具有許多功能,例如動態(tài)調(diào)度(在接口上調(diào)用方法),它還帶有運行時開銷。 因此,Java代碼可能更容易編寫,但通常仍會比C代碼慢。 但是,當(dāng)涉及純數(shù)字運算時,就像下面的示例一樣,有一些有趣的發(fā)現(xiàn)。
因此,無需進一步討論,這是示例C代碼:
test.c:
int compute(int i);int test(int i);int main(int argc, char** argv) {int sum = 0;for(int l = 0; l < 1000; l++) {int i = 0;while(i < 2000000) {if (test(i))sum += compute(i);i++;} }return sum; }test1.c:
int compute(int i) {return i + 1; }int test(int i) {return i % 3; }現(xiàn)在,主要功能的實際計算完全不重要。 關(guān)鍵是它經(jīng)常調(diào)用兩個函數(shù)(測試和計算),并且這些函數(shù)在另一個編譯單元(test1.c)中。 現(xiàn)在讓我們編譯并運行程序:
> gcc -O2 -c test1.c> gcc -O2 -c test.c> gcc test.o test1.o> time ./a.outreal?? ?0m6.693s user?? ?0m6.674s sys?? ?0m0.012s因此,此過程大約需要6.6秒 。 現(xiàn)在讓我們看一下Java程序:
Test.java
public class Test {private static int test(int i) {return i % 3; }private static int compute(int i) {return i + 1; }private static int exec() {int sum = 0; for (int l = 0; l < 1000; l++) {int i = 0; while (i < 2000000) {if (test(i) != 0) {sum += compute(i); }i++; }}return sum; }public static void main(String[] args) {exec(); } }現(xiàn)在讓我們編譯并執(zhí)行以下命令:
> javac Test.java> time java Testreal??? 0m3.411s user??? 0m3.395s sys???? 0m0.030s因此,花費3.4秒的時間 ,Java可以輕松完成此簡單任務(wù)(甚至包括JVM的緩慢啟動)。 問題是為什么? 當(dāng)然,答案是JIT可以執(zhí)行C編譯器無法執(zhí)行的代碼優(yōu)化。 在我們的例子中是函數(shù)內(nèi)聯(lián)。 當(dāng)我們在自己的編譯單元中定義了兩個微型函數(shù)時,編譯器無法在編譯test.c時內(nèi)聯(lián)這些函數(shù)。另一方面,JIT擁有所有方法,并且可以執(zhí)行主動內(nèi)聯(lián),因此編譯后的代碼速度更快。
那么,這是一個在現(xiàn)實生活中從未發(fā)生過的完全異國情調(diào)的虛構(gòu)例子嗎? 是的,沒有。 當(dāng)然,這是一個極端的情況,但是請考慮一下代碼中包含的所有庫。 所有這些方法都不能在C語言中進行優(yōu)化,而在Java中,字節(jié)碼的來源無關(guān)緊要。 由于所有JIT都存在于正在運行的JVM中,因此JIT可以對其核心內(nèi)容進行優(yōu)化。 當(dāng)然,C語言有一個卑鄙的技巧可以減輕這種痛苦:Marcos。 在我看來,這就是市長的原因之一,為什么C中如此之多的庫仍然使用宏而不是適當(dāng)?shù)墓δ?伴隨著它們帶來的所有問題和麻煩。
現(xiàn)在就在火焰戰(zhàn)爭開始之前:這兩種語言都有其長處和短處,并且在軟件工程領(lǐng)域都占有一席之地。 撰寫這篇文章僅是為了吸引您的注意,并想知道現(xiàn)代JVM每天都在發(fā)生。
翻譯自: https://www.javacodegeeks.com/2016/02/c-code-always-runs-way-faster-java-right-wrong.html
總結(jié)
以上是生活随笔為你收集整理的C代码的运行速度总是比Java快,对吧? 错误!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring jmx_JMX和Sprin
- 下一篇: 网页版安卓模拟器怎么用(网页版安卓模拟器