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

时间:2011-04-26 15:04:10

标签: java c++ performance

使用这种分而治之算法(编程Pearls p80)来查找在数组的任何连续子向量中找到的最大总和,Java程序比在Win7 x64上测试的C ++对应物更快,具有8GB RAM。

Java和C ++都在1个CPU内核上运行。

在JVM上进行了哪些优化才能实现这一目标?

使用JVM 1:

Java版“1.6.0_21”
Java(TM)SE运行时环境(版本1.6.0_21-b07)
Java HotSpot(TM)64位服务器VM(版本17.0-b17,混合模式)
VM Argument -Xmx12000m

使用JVM 2: jrockit-jdk1.6.0_24-R28.1.3-4.0.1
VM参数-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;        
    }
}

2 个答案:

答案 0 :(得分:6)

Java在运行时使用Just-in-Time编译器将字节码编译为您正在运行的体系结构的相应机器代码。在运行时,它会收集执行指标以检查代码正在执行的操作;如果它确定了一个不会改变代码结果的更优化机制,它将重新编译运行的代码,这意味着它针对最常用的路径进行了优化。

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

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

答案 1 :(得分:0)

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