在我的简单测试中,Java在递归算法速度比较上胜过c++
Java beats C++ on recursive algorithm speed comparison on my simple test
使用这种分治算法(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
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位处理器上运行相同的代码。
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么比较运算符如此快速
- 我可以使用 g++ 进行三种比较 (<=>) 吗?
- 比较字符数组
- 将模板化的类型与C++中的某些类/类型进行比较
- C++自定义比较函数
- 如何比较自定义类的std::变体
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- std::设置自定义比较器
- 布尔比较运算符是如何在C++中工作的
- C++将目录中的所有文件与::filesystem进行比较
- shell排序中的交换和比较
- 如何在C++中比较两个char数组
- catch框架有没有办法比较流或文件
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 智能指针作为无序映射键,并通过引用进行比较
- 比较if语句中的数组值和int值
- 对于循环变体比较
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- 比较两个大小不等的映射c++