在我的简单测试中,Java在递归算法速度比较上胜过c++

Java beats C++ on recursive algorithm speed comparison on my simple test

本文关键字:比较 c++ 速度 Java 简单 我的 测试 递归算法      更新时间:2023-10-16

使用这种分治算法(Programming Pearls p80)找到数组中任何相邻子向量的最大和,Java程序比在Win7 x64上使用8GB RAM测试的c++程序要快。

Java和c++都运行在一个CPU内核上。

在JVM上做了什么样的优化来实现这一点?

JVM 1使用:

Java版本"1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b07)
Java HotSpot(TM) 64位服务器VM (build 17.0-b17,混合模式)
虚拟机参数-Xmx12000m

JVM 2已使用:jrockit-jdk1.6.0_24-R28.1.3-4.0.1
虚拟机参数-Xmx12000m

c++编译器:

Visual Studio 2008 x64自带的默认Microsoft编译器

乘以 :

 //Java JVM 1, Oracle JRE
 //0x1fffffff: about 38s, sum 144115187270549505
 //0x2fffffff: about 56s, sum 324259171962716161
 //0x3fffffff: about 81s, sum 576460750692810753
 //Java JVM 2, Oracle JRockit jrockit-jdk1.6.0_24-R28.1.3-4.0.1
 //0x1fffffff: about 46s
 //0x2fffffff: about 69s
 //0x3fffffff: about 95s     
 //Cpp
 //0x1fffffff: around 45s, x64 Release
 //0x2fffffff: around 68s, x64 Release sum: 324259171962716161
 //0x3fffffff: around 93s, x64 Release sum: 576460750692810753, 
final int MAX = 0x3fffffff; 
Pearls1 pearls1 = new Pearls1();
pearls1.arr = new int[MAX];
for (int i = 0; i < MAX; i++)
{
    pearls1.arr[(int) i] = i;                
}
long startTime = System.nanoTime();
long sum = pearls1.binaryForce(0, MAX - 1);
long endTime = System.nanoTime();
long binaryForce(long lower, long upper) {
    //std::cout << "binaryForce("<< lower << ","<< upper <<")" << std::endl;
    if( lower > upper ) {
        return 0;
    } 
    if( lower == upper ) {      
        return Math.max( 0L, arr[(int) lower] ) ;       
    }
    long middle = ( lower + upper ) /2 ;
    long lmax = 0,  sum = 0;
    for( long i = middle; i >=lower; i-- ) {
        sum += arr[(int) i];        
        lmax = Math.max( lmax, sum);
    }
    long rmax = 0;
    sum = 0;
    //for( long i = middle+1; i <= upper; i++ ) {
    for( long i = upper; i > middle; i-- ) {
        sum += arr[(int) i];
        rmax = Math.max(rmax, sum);     
    }
    long theMax = lmax+rmax;
    long binarySumLeft = binaryForce(lower, middle);
    long binarySumRight = binaryForce(middle+1, upper);
    if( theMax > binarySumLeft && theMax > binarySumRight ) {
        return theMax;
    }
    else if( binarySumLeft > theMax && binarySumLeft > binarySumRight ) {
        return binarySumLeft;
    }
    else if ( binarySumRight > theMax && binarySumRight > binarySumLeft ) {
        return binarySumRight;
    }
    else {
        return theMax;      
    }
}
 int main(...) {
    MAX = 0x3fffffff;
    arr = new long[MAX];
    for( long i=0;i<MAX;i++) {
        //arr[i] = rand();
        arr[i] = i;
    }
    timeb startTime, endTime;
    ftime( &startTime);
    std::cout << "Start time: " << startTime.time << " sec, " << startTime.millitm << " ms" << std::endl;
    sum = binaryForce(0, MAX-1);
    std::cout << "sum: " << sum <<std::endl;
    ftime( &endTime);
    std::cout << "End time: " << endTime.time << " sec, " << endTime.millitm << " ms" << std::endl;
    long runTimeSec = endTime.time - startTime.time;
    long runTimeMs = endTime.millitm - startTime.millitm;
    std::cout << "Run time: " << runTimeSec << " sec, " << runTimeMs << " ms" << std::endl;
 }
long long binaryForce(long lower, long upper) {
    //std::cout << "binaryForce("<< lower << ","<< upper <<")" << std::endl;
    if( lower > upper ) {
        return 0;
    } 
    if( lower == upper ) {        
        return std::max( 0L, arr[lower] ) ;        
    }
    long middle = ( lower + upper ) /2 ;
    long long lmax = 0,  sum = 0;
    for( long i = middle; i >=lower; i-- ) {
        sum += arr[i];        
        lmax = std::max( lmax, sum);
    }
    long long rmax = 0;
    sum = 0;
    //for( long i = middle+1; i <= upper; i++ ) {
    for( long i = upper; i > middle; i-- ) {
        sum += arr[i];
        rmax = std::max(rmax, sum);        
    }
    long long theMax = lmax+rmax;
    long long binarySumLeft = binaryForce(lower, middle);
    long long binarySumRight = binaryForce(middle+1, upper);
    if( theMax > binarySumLeft && theMax > binarySumRight ) {
        //std::cout << arr[theMax] << std::endl;
        return theMax;
    }
    else if( binarySumLeft > theMax && binarySumLeft > binarySumRight ) {
        //std::cout << arr[binarySumLeft] << std::endl;
        return binarySumLeft;
    }
    else if ( binarySumRight > theMax && binarySumRight > binarySumLeft ) {
        //std::cout << arr[binarySumRight] << std::endl;
        return binarySumRight;
    }
    else {
        //std::cout << arr[theMax] << std::endl;
        return theMax;        
    }
}

Java在运行时使用即时编译器将字节码编译成适合您所运行的体系结构的适当机器码。当它运行时,它收集执行指标来检查代码正在做什么;如果它确定了一个不改变代码结果的更优机制,它将重新编译运行的代码,这意味着它针对最常用的路径进行了优化。

c++没有这样做,因为它是使用一系列静态优化进行优化的。Java可以做到这些,但是JIT意味着优化也可以针对您正在使用的数据。

你也没有说你正在使用哪个JVM。不同的jvm具有不同的特性。例如,JRockit实际上会比标准Oracle JVM优化得更好,尽管它也需要更长的预热时间。

我在这里猜测,但c++中的int表示为32位(4字节)——在64位系统上,内核需要执行2个操作来访问int: 1/读取WORD(64位),然后2/应用AND掩码将其减少到32位。据我所知,JVM可能会在内部将int存储为64位,但只有在您阅读本文时,您才会应用AND位运算符(即求和/比较/等将在封面下的64位值上完成)。尝试更改c++代码以使用WORD数据结构(64位)或在32位处理器上运行相同的代码。