使用这种分而治之算法(编程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;
}
}
答案 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位处理器上运行相同的。