java 32和64位之间空循环的巨大性能差异

java 32和64位之间空循环的巨大性能差异,java,performance,32bit-64bit,jvm-hotspot,Java,Performance,32bit 64bit,Jvm Hotspot,在我的空闲时间,我最近为多线程数学运算建立了一个框架,为了测试它,我计算了第一个千个素数 但是我需要花费更多的时间,所以我将这段代码插入到prime计算中: for (int i = 0; i < 1000000; i++) { // Nothing. } for(int i=0;i

在我的空闲时间,我最近为多线程数学运算建立了一个框架,为了测试它,我计算了第一个千个素数

但是我需要花费更多的时间,所以我将这段代码插入到prime计算中:

for (int i = 0; i < 1000000; i++)
{
    // Nothing.
}
for(int i=0;i<1000000;i++)
{
//没什么。
}
很长一段时间以来,我在64位机器上编写和编译代码,并在许多32位机器上进行测试

然后我在64位机器上运行它,发现了巨大的性能差异

import java.util.ArrayList;
import java.util.Collection;
public class Test {
public static void main(String[] args)
{
    long start = System.currentTimeMillis();
    int j = 2;
    ArrayList<Integer> res = new ArrayList<Integer>();
    for (int k = 0; k < 50000; k++)
    {
        Collection<Integer> partres = work(k);
        if (partres != null)
            res.addAll(work(k));
    }
    long end = System.currentTimeMillis();
    System.out.println("Done in " + (end-start) + " ms.");
}
public static Collection<Integer> work(Integer j) {
    for (int i = 0; i < 1000000; i++)
    {
        // Nothing.
    }
    if (isPrime(j))
    {
        ArrayList<Integer> res = new ArrayList<Integer>();
        res.add(j);
        return res;
    }
    else
        return null;
}
static boolean isPrime(int n) {
    if (n == 2) return true;
    if (n%2==0) return false;
    for(int i = 3; i * i <= n; i += 2) 
        if(n%i==0)
            return false;
    return true;
}
}

对于相同的代码,一个完全相似的64位机器总是使用-server JIT编译器,而您的32位JVM可能使用-client JIT编译器

当飞机起飞时-服务器编译器会看到如下内容:

for (int i = 0; i < 1000000; i++)
{
  // Nothing.
}
for(int i=0;i<1000000;i++)
{
//没什么。
}
它会注意到循环什么也不做,并删除它!你的循环什么都不做,将被优化为什么都不做


为了挫败这种优化,您必须让循环做一些事情——例如,它可以将所有的
i
异或在一起——并利用结果。在windows上,默认情况下,32位JVM将使用
-client
JVM,64位JVM将使用
-server
。服务器JVM在删除不起任何作用的代码方面更具攻击性。e、 g.空循环。您会发现,无论计数限制如何,这样的循环所需的时间大致相同,因为它取决于检测和消除循环所需的时间。尝试将第二个计时循环添加到同一个方法中,您会发现,无论您将最大值设置为什么(假设它不是无限循环),几乎不需要花费时间。这是因为该方法将在第二个循环开始时编译


顺便说一句:我会使用nanoTime并重复运行您的测试至少几秒钟。

编译器应该优化这个空循环。您是否总是在虚拟机上测试它,或者64位是一个普通的(或者应该称之为什么)机器?我知道空循环是一个很差的基准测试方法。但关键是,同一个编译后的文件有巨大的性能差异,这取决于我是否在64位机器上运行它。我在虚拟机和“本机”64和32台机器上测试了它。代码可能会保留。服务器JVM仍然可以消除相对复杂(如果没有意义的话)的代码。@PeterLawrey,对。Brian Goetz推荐我在他的JCiP书IIRC中描述的XOR方法。不同于仅仅把i加在一起,它不能变成简单的乘法运算。这也是为什么我们应该利用循环的结果,即使用println().+1链接到文档。我试着在32位机器上用“-server”运行代码,运行时间与64位机器差不多。对于Oracle JDK和OpenJDK来说,
server
VM也是x86-64 Linux上的默认值。我不确定32位Linux。为什么Oracle不将其32位JVM与
server
作为默认值一起提供?几年前,当32位机器更可能内存不足时,这就有了一定的意义。事实上,有人在任何不古老的东西上运行32位Windows吗?