0

In my free time i recently made a framework for multi-threaded math operations, and to test it i calculated the first couble of thousand prime numbers.

But i needed it to take more time, so i inserted this code into the prime calculation:

for (int i = 0; i < 1000000; i++)
{
    // Nothing.
}

For a long time, i write and compiled the code on a 64bit machine, and tested it on a number of 32 bit machines.

Then i ran it on a 64 bit machine, and noticed a massive performance difference.

With the same code, a completely similar 64 machine takes <100ms to do, what a 32 machine uses ~52000ms to do (2 virtual machine on the same host).

I've tested on Windows and Ubuntu on different computers, and using the same .class file, i still get this massive 32bit vs 64bit difference.

Here is a quick code that you can use the replicate the performance difference.

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;
}
}

And here is the .class file i compiled it to.

Now my question.

I know that there is a performance gain by using a 64bit machine, but that doesn't explain this massive difference. So does anybody have any idea why this is happening?

4

2 回答 2

4

64 位 Java 始终使用 -server JIT 编译器,而您的 32 位 JVM 可能使用 -client JIT 编译器。

当C2又名。-server 编译器看到如下内容:

for (int i = 0; i < 1000000; i++)
{
  // Nothing.
}

它会注意到循环什么都不做,并将其删除!您什么都不做的循环将被优化为什么都没有。

为了阻止这种优化,你必须让循环做一些事情——i例如,它可以对所有这些进行异或运算——并利用结果。然后循环看起来对编译器来说就像真正的工作,并且代码将被保留。

于 2012-02-19T21:36:34.363 回答
3

在 Windows 上,它将-client默认使用 JVM 用于 32 位和-server64 位 JVM。服务器 JVM 更积极地删除不执行任何操作的代码。例如空循环。无论计数限制如何,您都会发现这样的循环花费的时间大致相同,因为它取决于检测和消除循环所需的时间。尝试在同一方法中添加第二个定时循环,您会发现无论您将最大值设置为多少(假设它不是无限循环),它几乎不需要时间这是因为该方法将在第二个循环时编译开始。

http://docs.oracle.com/javase/1.5.0/docs/guide/vm/server-class.html

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

于 2012-02-19T21:47:44.853 回答