鍍金池/ 問答/Java  C++/ Java可能比C++快嗎?為什么?

Java可能比C++快嗎?為什么?

這是一段用C++寫的計算十萬以內(nèi)的回文素數(shù)算法。

#include <iostream>
using namespace std;
int main()
{
    int input_num=100000;
    int pp_count=0;
    for(int each=2; each<=input_num; each++)
    {
        int factorization_lst=0;
        for(int factor=1; factor<=each; factor++)
            if(each%factor==0&&!(factor>each/factor))
                factorization_lst++;
        if(factorization_lst==1)
        {
            int antitone=0,each_cpy=each;
            while(each_cpy)
            {
                antitone=antitone*10+each_cpy%10;
                each_cpy/=10;
            }
            if(antitone==each)
            {
                pp_count++;
                cout<<pp_count<<':'<<each<<endl;
            }
        }
    }
    return 0;
}

稍微做一下修改的Java版,加了計時相關的部分。

public class main {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        int input_num = 100000;
        int pp_count = 0;
        for (int each = 2; each <= input_num; each++) {
            int factorization_lst = 0;
            for (int factor = 1; factor <= each; factor++)
                if (each % factor == 0 && !(factor > each / factor))
                    factorization_lst++;
            if (factorization_lst == 1) {
                int antitone = 0, each_cpy = each;
                while (each_cpy != 0) {
                    antitone = antitone * 10 + each_cpy % 10;
                    each_cpy /= 10;
                }
                if (antitone == each) {
                    pp_count++;
                    System.out.println(pp_count + ":" + each);
                }
            }
        }
        System.out.println(System.currentTimeMillis() - start);
    }
}

執(zhí)行結果:
Codeblocks
eclipse
同樣的算法,C++用了230s,Java只用了124s。這是為什么呢,不是說C++的速度更快嗎?

注:運行環(huán)境是樹莓派3B的官方raspbian(在我的筆記本上運行過,但僅相差一秒不明顯,java17s),C++和Java分別用的默認倉庫的codeblocks和eclipse(都不是最新版本,eclipse的版本是2012年的3.8.1,codeblocks是2016年的16.01),gcc已經(jīng)默認開啟了-O2優(yōu)化選項,但還是如此相差懸殊。已經(jīng)看過類似于這樣的解釋文章。但還是不太明白。我的代碼只有一個main,沒有內(nèi)聯(lián)函數(shù)。Java編譯器難道不也是只分指令集的嗎,怎么能夠編譯出更加優(yōu)化的字節(jié)碼呢?而且這段代碼,Java還能怎么優(yōu)化呢?


追加:
按照@Untitled(sf沒有艾特的功能嗎)的提示,做下一個實驗證明JIT對Java執(zhí)行速度的影響。這次使用命令行直接編譯,繞過IDE的影響。個人感覺兩分鐘僅輸出百來行的話IO操作對速度的影響可忽略不計。
(由于這次圖片屢次上傳失敗因此只貼出shell相關操作,加上C++編譯結果)

pi@raspberrypi:~/workspace/testjava/src $ javac main.java
pi@raspberrypi:~/workspace/testjava/src $ java main
1:2
# 省略計算輸出
113:98689
110494
# 110秒,比在eclipse中執(zhí)行的速度還快,接下來禁用JIT
pi@raspberrypi:~/workspace/testjava/src $ java -Xint main
1:2
# 省略計算輸出
113:98689
797514
# 797秒,明顯慢于使用JIT的
pi@raspberrypi:~/workspace/testjava/src $ 
# C++編譯
pi@raspberrypi:~/cpplearn $ g++ -o main main.cpp
pi@raspberrypi:~/cpplearn $ time ./main
1:2
# 省略計算輸出
113:98689

real    4m5.606s
user    4m5.581s
sys    0m0.000s
#245秒,接下來啟用-O2選項
pi@raspberrypi:~/cpplearn $ g++ -O2 -o main main.cpp
pi@raspberrypi:~/cpplearn $ time ./main
1:2
# 省略計算輸出
113:98689

real    3m50.631s
user    3m50.384s
sys    0m0.010s
# 230秒,快了一點,和在codeblocks編譯的速度差不多
pi@raspberrypi:~/cpplearn $ 

JIT確實是大幅度提升了Java的執(zhí)行速度。(從797110)

看了一下JIT的相關資料(1,2),感覺就算是這樣,也不過就是不經(jīng)過JVM直接執(zhí)行了Java代碼,這和C++的編譯原理不是一樣的嗎?最多只是持平,怎么還會快這么多呢?
其實我不懂怎么反匯編,所以也不知道這怎么回事。我的循環(huán)也不是空的??赡艿脑挘蚁胫繨ava的JIT是怎么加快執(zhí)行這段代碼的速度的。


追加:
經(jīng)過幾次實驗,發(fā)現(xiàn)在x86/x64架構中無論是在Windows還是Linux,實體機還是虛擬機,C++的速度在總體上都比Java更勝一籌。arm的設備我除了樹莓派,剩下的只有Android手機了。我準備在一臺諾基亞7(驍龍630,4GB,原生Android 8.0,無root,已經(jīng)盡可能關掉所有后臺應用,在我看來是相當穩(wěn)定的測試環(huán)境。)上面進行測試。用來測試的軟件有兩個在手機上運行的IDE(部署Linux Deploy還是太麻煩了)AIDE (用來編譯Java代碼)和CIDE (用來編譯C++代碼,編譯器為aarch64的gcc7.2)。

由于在CIDE無法顯示程序執(zhí)行時間,因此這次在C++代碼也加入了計時

#include <iostream>
#include <ctime>
using namespace std;
int main()
{
    clock_t start = clock();
    int input_num = 100000;
    int pp_count = 0;
    for (int each = 2; each <= input_num; each++)
    {
        int factorization_lst = 0;
        for (int factor = 1; factor <= each; factor++)
            if (each % factor == 0 && !(factor > each / factor))
                factorization_lst++;
        if (factorization_lst == 1)
        {
            int antitone = 0, each_cpy = each;
            while (each_cpy)
            {
                antitone = antitone * 10 + each_cpy % 10;
                each_cpy /= 10;
            }
            if (antitone == each)
            {
                pp_count++;
                cout << pp_count << ':' << each << endl;
            }
        }
    }
    cout << 1000*(clock() - start) / CLOCKS_PER_SEC;
    return 0;
}

優(yōu)化選項改成使用-O3(默認為-Os)

執(zhí)行結果:(這已經(jīng)是我挑選出來所用時間最短的了)

C++用了43s

Java用了37s

.....
(已經(jīng)經(jīng)過多次測試)


追加:
聽從Untitled的建議使用clang編譯(Raspbian默認沒有安裝,還得自己apt install clang一下)
速度有了質(zhì)的飛躍。(但還沒越過Java)
不使用優(yōu)化選項:3m22s(202s)
使用-O2選項:3m05s(185s)(使用-O3與-O2的執(zhí)行速度是差不多的)

順帶一提,我再次執(zhí)行java版時去掉計時的那兩行代碼,

    //long start = System.currentTimeMillis();
    //System.out.println(System.currentTimeMillis() - start);

然后使用time命令計時,結果時間延長了零點幾秒...


追加:
今晚身體不適,但還是抽出一點時間寫了Android上的測試應用。(,下載)
在編寫過程中,我已經(jīng)盡量保證了公平。
因為今晚急著早點休息,暫時未進行充分的測試(但大體上C++比Java快很多)。大家可以自行下載測試一下,晚些時候我再發(fā)布一下詳細測試結果。

主要代碼:

MainActivity.java

package ryuunoakaihitomi.javacppperfcomparison;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Toast;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends Activity {

    public static final String TAG = "JCPC";

    static {
        System.loadLibrary("native-lib");
    }

    @SuppressWarnings("ConstantConditions")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_main);
        getActionBar().setTitle("logcat -s JCPC");
        Log.i(TAG, "Finding palindromic primes within 100,000.(Waiting for 3s)");
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        final long jTime = pcTimer(true);
                        final long cTime = pcTimer(false);
                        runOnUiThread(new Runnable() {
                            @SuppressLint("DefaultLocale")
                            @Override
                            public void run() {
                                Toast.makeText(getApplicationContext(), String.format("java:%d\ncpp:%d", jTime, cTime), Toast.LENGTH_LONG).show();
                                finish();
                            }
                        });
                    }
                }).start();
            }
        }, 3000);
    }

    public native void cpp();

    long pcTimer(boolean isJava) {
        long lStart = System.currentTimeMillis();
        if (isJava)
            Java.kernel();
        else
            cpp();
        long lTime = System.currentTimeMillis() - lStart;
        Log.i(TAG, "total time:" + lTime);
        return lTime;
    }
}

Java.java

package ryuunoakaihitomi.javacppperfcomparison;

public class Java {

    static {
        System.loadLibrary("native-lib");
    }

    static void kernel() {
        int iInputNumber = 100000;
        int iPalprimeCount = 0;
        for (int iEach = 2; iEach <= iInputNumber; iEach++) {
            int iFactorizationList = 0;
            for (int iFactor = 1; iFactor <= iEach; iFactor++)
                if (iEach % iFactor == 0 && !(iFactor > iEach / iFactor))
                    iFactorizationList++;
            if (iFactorizationList == 1) {
                int iAntitone = 0, iEachCopy = iEach;
                while (iEachCopy != 0) {
                    iAntitone = iAntitone * 10 + iEachCopy % 10;
                    iEachCopy /= 10;
                }
                if (iAntitone == iEach) {
                    iPalprimeCount++;
                    ResultPrint(iPalprimeCount, iEach);
                }
            }
        }
    }

    public static native void ResultPrint(int c, int e);
}

native-lib.cpp

#include <jni.h>
#include <android/log.h>
#include <string>

using namespace std;

void kernel();

void kernel_log(string, int, int);

extern "C" JNIEXPORT void

JNICALL
Java_ryuunoakaihitomi_javacppperfcomparison_MainActivity_cpp(
        JNIEnv *,
        jobject /* this */) {
    kernel();
}

void kernel() {
    int input_num = 100000;
    int pp_count = 0;
    for (int each = 2; each <= input_num; each++) {
        int factorization_lst = 0;
        for (int factor = 1; factor <= each; factor++)
            /*Expression can be simplified to 'factor <= each / factor' less... (Ctrl+F1)
            This inspection finds the part of the code that can be simplified, e.g. constant conditions, identical if branches, pointless boolean expressions, etc.*/
            if (each % factor == 0 && factor <= each / factor)
                factorization_lst++;
        if (factorization_lst == 1) {
            int antitone = 0, each_cpy = each;
            while (each_cpy) {
                antitone = antitone * 10 + each_cpy % 10;
                each_cpy /= 10;
            }
            if (antitone == each) {
                pp_count++;
                kernel_log("c", pp_count, each);
            }
        }
    }
}

void kernel_log(string t, int c, int e) {
    __android_log_print(ANDROID_LOG_DEBUG, "JCPC", "%s %d:%d", t.c_str(), c, e);
}

extern "C"
JNIEXPORT void JNICALL
Java_ryuunoakaihitomi_javacppperfcomparison_Java_ResultPrint(JNIEnv *, jobject, jint c,
                                                             jint e) {
    kernel_log("j", c, e);
}

追加:

準備環(huán)境:

  • 測試之前已經(jīng)完全運行過一次
  • 禁用Xposed,暫時凍結了占用后臺的應用,電量至少在30%保證穩(wěn)定供電

實驗三次取各自的最小值,實驗結果:
說明:表格前四列的值均來自于android.os.Build中對應名稱的常量

MODEL MANUFACTURER DISPLAY SDK_INT Java耗時 C++耗時
GT-I9300 samsung lineage_i9300-userdebug 7.1.2 NJH47F 0f9e26b899 25 192169 171928
Redmi 4A Xiaomi NJH47F 25 66009 31907
m2 Meizu Flyme 6.3.0.0A 22 37722 34654
A2 softwinner 升級版四核2G運存 19 239865 202402
Redmi Note 3 Xiaomi OPM1.171019.018 27 22299 18105
TA-1041 HMD Global 00CN_1_34E 26 37310 20234
HTC 802t htc LRX22G release-keys 21 48211 125279

可以看出,絕大多數(shù)的arm Android設備運行C++的速度快過Java。但是最后這一行的結果超出了預料。
僅僅是測試之一,讀數(shù)主要看日志

這個設備的CPU是驍龍600。(好奇怪......)

另:我前兩天買了一個香橙派zero plus,用的全志H5。C++45s,java70s。

我的所有arm設備已經(jīng)測試完成,我能不能得到以下結論。

在一小部分的arm指令集架構設備中,Java的運行速度會快于C++。

想知道原因。

回答
編輯回答
失魂人

1) 看下這個https://benchmarksgame-team.p...,這個基本上Cpp無一落敗
2) 除了-O2外,還有-O3,還有其他的編譯參數(shù),請參見GCC手冊
3) JVM默認是用空間換時間的,所以這么對比不是很適合

你的代碼,我在未優(yōu)化一行代碼的情況下,使用-O3來測試(實際上release都是-O3),運算3次都比Java快,這中間還包括加載程序啟動的時間,怎么得出結論會比java慢呢。

當然,C++對程序員要求很高,不了解內(nèi)存模型、編譯原理什么的,是很難寫出高質(zhì)量的C++的,在這一點上,java就好很多

最近買了一個樹莓派3B+,特意跑了下這個程序,從性能上看,C++比java在Arm上略快,優(yōu)勢不明顯,另外寫了一個rust版本的代碼,算法上未優(yōu)化,性能跟C++接近,在release情況下比Java略快。

fn main() {
    let input_num=100001;
    let mut pp_count =0;
    for  each in 2..input_num {
        let mut factorization_lst=0;
        for  factor in 1..each+1 {
            if each%factor==0 &&!(factor>each/factor) {
                factorization_lst += 1;
            }
        }
        if factorization_lst==1
        {
            let mut antitone =0;
            let mut each_cpy =each;
            while each_cpy != 0
            {
                antitone=antitone*10+each_cpy%10;
                each_cpy/=10;
            }
            if antitone==each
            {
               pp_count += 1;
               println!("{}:{}", pp_count, each);
            }
        }
    }
}

從CPU上來,基本上在運行期這3個程序都是跑滿單核的(樹莓派3B+有4個core),但內(nèi)存上來看,C++和rust有明顯優(yōu)勢,大概為java版本的1/10.
這個測試從測試結果來看,這幾個語言的運行性能差異沒那么大,分析了下有幾個原因
1) 對于int數(shù)據(jù)類型,在java C++ rust里都是原生類型,原生的在計算時差別不大,對于java來說,如果是Integer可能有性能損耗。
2) 只跑了一個核,沒有多核之間的數(shù)據(jù)傳遞等
3) 沒有用到遞歸、值傳遞、引用傳遞、值拷貝等特性,差異不大。

結論: java是一個性價比比較好的語言,運行性能上或許不是最優(yōu),但開發(fā)效率很好,不像其他的語言要考慮跨平臺移植問題、編譯參數(shù)問題等。
PS 未來看好rust

2017年12月16日 21:05
編輯回答
哎呦喂

java 17s, c++ 14s
測試了10多遍,還是這個結果。

2018年4月15日 12:57
編輯回答
舊言

LeetCode上很多題的最佳解法,java運行的甚至比C快,也一直很疑惑。

2017年3月20日 23:26
編輯回答
敢試

不會寫 C++ 的人寫出來的 C++ 確實可以比 Java 慢,甚至比沒有任何優(yōu)化直接解釋執(zhí)行的 Java 慢。
但是會寫 C++ 的人永遠可以寫出完虐解釋執(zhí)行的 Java 的代碼,但是 JIT 的 Java 還是可以比 C++ 快,因為它能做一些依賴運行時才能知道的信息才能做的優(yōu)化。這也是現(xiàn)在 C++ 編譯器進化的方向,一個是加入運行時信息的優(yōu)化,一個是 link time 優(yōu)化。

歸根結底,比較兩個語言的速度是耍流氓,只能比寫代碼的人的質(zhì)量和編譯器的質(zhì)量。

題主的問題應該恰是一個運行時掌握的信息能進行更多優(yōu)化的例子。

幫題主重寫了下 C++ 和 Java 的代碼:

測試環(huán)境:x86_64 架構,C++/LLVM 6.0,Java/HotSpot 18.3

C++ 版用時 0.008s (time 命令)
Java 版用時 0.045340767000000004s (System.nanoTime)

可見 C++ 版算上前后的時間還是比 Java 快一個數(shù)量級。

(即便 Java 版在計時前運行同樣地代碼上萬次來預熱,多次運行結果也沒有變化,因此測量的結果是科學的。)

附代碼:

#include <iostream>

using namespace std;

constexpr int N = 100000;
bool C[N + 5];

int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);

  int c = 0;

  for (int i = 2; i < N; ++i) {
    if (!C[i]) {
      for (int j = i + i; j < N; j += i) {
        C[j] = true;
      }

      int z = 0;
      for (int k = i; k != 0; ) {
        z *= 10;
        z += k % 10;
        k /= 10;
      }

      if (z == i) {
        cout << ++c << ':' << i << '\n';
      }
    }
  }
}
class Two {

  static final int N = 100000;
  static final boolean[] C = new boolean[N + 5];

  public static void main(String[] args) {
    long start = System.nanoTime();

    int c = 0;

    for (int i = 2; i < N; ++i) {
      if (!C[i]) {
        for (int j = i + i; j < N; j += i) {
          C[j] = true;
        }

        int z = 0;
        for (int k = i; k != 0; ) {
          z *= 10;
          z += k % 10;
          k /= 10;
        }

        if (z == i) {
          System.out.println(++c + ":" + i);
        }
      }
    }

    System.out.println("time: " + (System.nanoTime() - start) * 1e-9 + "s");
  }
}
2018年8月1日 05:09
編輯回答
情未了

我什么都不知道,我看見GGWP我我就點贊了。

2018年8月20日 17:33
編輯回答
嫑吢丕

我在學校的老服務器上跑了一遍你給的代碼,cpp的用系統(tǒng)自帶的time計時,java的用程序自己的結果,結果是cpp的25.125s的用戶時間,25.130s的墻上時鐘時間;java的25.240s的用戶時間,25.250s的墻上時鐘時間,自稱25114毫秒(25.114s)運行結束,感覺好像是差不多的。為了排除I/O操作的影響,我把除了java版的最后一句輸出外的cpp和java的所有輸出都注釋掉再試了一次,結果還是差不多。所以我打算把十萬改成一百萬,還沒跑完,有空再把結果放上來哈哈哈哈哈哈哈哈哈哈哈哈哈

以上是非常臨時且不嚴謹?shù)膶嶒灲Y果,沒空做大量的對照實驗。我想某些情況下,代碼邏輯的完全相同的java程序比cpp程序或c程序快的原因應該就是編譯器優(yōu)化和個別操作實現(xiàn)的差異的原因,除此之外暫時想不到別的原因。不管是什么語言寫的程序,實際“運行”的一定是機器指令,cpp和c編譯后的正文部分是一堆機器指令序列,java編譯后是jvm的機器指令序列(是的吧?),但執(zhí)行的時候還要jvm去解釋字節(jié)碼,解釋執(zhí)行的時候仍要執(zhí)行宿主機的機器指令,不過好像還有JIT的說法?(不是很熟悉java)。所以我相信理論上來講,不使用JIT的話,java肯定是沒有cpp和c快的(在“相同的程序”的意義下,但這個“相同”又很難定義,你懂就好),因為java還要“解釋”,然后才能“執(zhí)行”。因此我覺得一定是編譯器的鍋,但也只是覺得,我手上也沒有什么實驗結果。

你可以試試能不能把JIT關了,再比較結果?

有興趣的話可以多試試不同的程序,簡單的,復雜的,多種程序對比(記得java好像會自動跳過一些無意義的循環(huán)體,比如空轉的循環(huán)體,這點要注意)。其中簡單的程序可以對編譯出來的文件進行反匯編,分析理論執(zhí)行效率,找到導致差異的原因。


試了一下在樹莓派3B上跑,結果比題主的慢多了,但java確實比cpp快,用的和樓主一樣的代碼,cpp跑了4分多鐘,java跑了將近2分鐘,quite interesting :D。cpp和java均使用了默認編譯參數(shù),g++版本是4.9.2,javac版本是1.8.0_65,java版本是1.8.0_65-b17。

然后我又給cpp版的加了-O2參數(shù),時間提升到3分40多秒——還是沒java版的快emmmmm

這就比較神奇了,于是我又試了一下別的程序——我自己寫了個斐波那契數(shù)列求值的——這回舒服了,cpp的1.6s,java的3.4s,更多詳情日后再說,先掃墓去了以下是測試代碼

遞歸求斐波那契數(shù)列

測試代碼

// test.cc
#include <iostream>

using namespace std;

int fibo(int n)
{
    switch(n)
    {
        case 1: return 1;
        case 2: return 1;
        default: return fibo(n - 1) + fibo(n - 2);
    }
}

int main()
{
    cout << fibo(40) << endl;
    return 0;
}
// main.java
public class main {
  private static int fibo(int n) {
    switch(n) {
      case 1: return 1;
      case 2: return 1;
      default: return fibo(n - 1) + fibo(n - 2);
    }
  }

  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    System.out.println(fibo(40));
    System.out.println(System.currentTimeMillis() - start);
  }
}
// Makefile
main: test.cc main.java
    g++ test.cc -o test -O2
    javac main.java
# test.sh
time(./test) 1>cpp.res 2>cpp.time
time(java main) 1>java.res 2>java.time

測試命令

make
./test.sh

結果

clipboard.png

那個prompt是用powerline-shell

反正是要燒CPU,就沒用動態(tài)規(guī)劃了(其實是忘了怎么動態(tài)規(guī)劃了)。

更多的5次重復實驗

總結

可以初步推斷,簡單的遞歸cpp完勝java(除了“簡單的”,還需要補充哪些限制,歡迎評論)。

然后我又測試了瘋狂swap兩個int

反復交換變量值

測試代碼

// test.cc
#include <iostream>
#include <cstdlib>

using namespace std;


int main(int argc, char *argv[])
{
    int a = 1, b = 2;
    int times = atoi(argv[1]);
    for(int i = 0; i < times; i++)
    {
        a = a + b;
        b = a - b;
        a = a - b;
    }
    return 0;
}
// main.java
public class main {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        int a = 1;
        int b = 2;
        int times = Integer.parseInt(args[0]);
        for(int i = 0; i < times; i++) {
            a = a + b;
            b = a - b;
            a = a - b;
        }
        System.out.println(System.currentTimeMillis() - start);
    }
}
// Makefile
main: test.cc main.java
    g++ test.cc -o test
    javac main.java

注意:為什么不優(yōu)化了呢,因為我發(fā)現(xiàn)優(yōu)化的話cpp會偷懶,它知道實際上瘋狂swap兩個沒用的東西又沒輸出等于啥都沒干,所以會直接退出程序(O2優(yōu)化),或空循環(huán)(O1優(yōu)化)

# test.sh
time(./test $1) 2>cpp.time
time(java main $1) 1>java.res 2>java.time
cat cpp.time
cat java.res

測試命令

make
./test.sh 1000
./test.sh 10000
./test.sh 100000
./test.sh 1000000
./test.sh 10000000
./test.sh 100000000
./test.sh 1000000000

結果

clipboard.png

總結

看不太懂ATT風格的匯編代碼,關閉了優(yōu)化之后,cpp編譯出來的二進制文件中多出了str(store register?)指令,瘋狂訪問內(nèi)存勢必會大大增長代碼執(zhí)行時間……至于java,用javap -c main反匯編了一下,確實是有看到iloadistore的命令(我不會jvm的匯編,這兩句應該就是從內(nèi)存里加載到寄存器和從寄存器存儲到內(nèi)存的指令吧),看起來為什么java訪問內(nèi)存的速度比cpp快這么多呢,我也不知道哈哈哈哈哈,可能需要更深入地了解java的內(nèi)存模型之類的,另外這兩個指令是不是總是會導致jvm去訪問內(nèi)存呢?還是可能只是會訪問寄存器?顯然如果是后者,速度必然比前者快得多,然而這個問題我也不知道答案。

不會寫64位的arm匯編程序,不然我可以試試用匯編瘋狂交換兩個寄存器的值會不會比java版的還快。

總結

你要是說在都不優(yōu)化的情況下同等代碼java跑得比cpp或c快我是不信的,一個半解釋執(zhí)行的程序干得過編譯執(zhí)行的程序我也是不信的。我認為,導致等效的java程序跑得比記者cpp程序還快的原因應該就是編譯器(速度全靠一手編譯器)。至于上面的結果,我無可奉告也不知道如何解釋,雖然至少遞歸方面cpp勝出了emmm,才疏學淺,沒有辦法究其原因

技不如人,甘拜下風
ggwp

又在手機上小測試了一下,一加5T,驍龍835CPU(ARM架構),終端模擬器使用Termux,編譯器使用clangecj,java虛擬機使用安卓自帶的dalvikvm,開啟了jit,結果java跑了86秒,cpp跑了26秒。

編譯cpp代碼的命令(這里的g++實際上還是clang

g++ test.cc -o test -O2

編譯java代碼使用的命令參考這里

運行命令參數(shù)加了-Xusejit:true,-Xusejit:1也試過了,結果也是86秒。

2018年7月19日 11:09
編輯回答
尐飯團

測試了下,在我的筆記本上跑,c++21秒(沒開O2),java22秒,基本差不多。c++開了O2的話17秒。
可能是樹莓派的c++編譯器有毒。。。

2017年9月7日 07:16
編輯回答
心癌

看下這個就知道了java c++ 性能比較 感覺還是c++快

2018年1月12日 09:16