在我的空闲时间里,我最近制作了一个多线程数学运算的框架,并测试它,我计算了千元素数的第一个数。
但我需要花费更多时间,所以我将此代码插入到主要计算中:
for (int i = 0; i < 1000000; i++)
{
// Nothing.
}
很长一段时间,我在64位机器上编写并编译代码,并在许多32位机器上进行测试。
然后我在64位机器上运行它,并注意到了巨大的性能差异。
使用相同的代码,完全类似的64台机器需要<100ms才能完成,32台机器使用~52000ms(同一台主机上有2台虚拟机)。
我已经在不同的计算机上测试过Windows和Ubuntu,并使用相同的.class文件,我仍然可以获得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;
}
}
here is the .class file i compiled it to.
现在我的问题。
我知道使用64位机器会带来性能提升,但这并不能解释这种巨大的差异。所以有人知道为什么会这样吗?
答案 0 :(得分:4)
64位Java总是使用-server JIT编译器,而32位JVM可能使用-client JIT编译器。
当C2又名。 -server编译器看到如下内容:
for (int i = 0; i < 1000000; i++)
{
// Nothing.
}
它会注意到循环什么也没做,删除了它!你的循环什么都不做,将被优化为什么。
为了阻止这种优化,你必须让循环做一些事情 - 它可以将所有i
放在一起,例如 - 并且使用结果。然后循环看起来像编译器的实际工作,代码将被保留。
答案 1 :(得分:3)
在Windows上,默认情况下,-client
JVM用于32位,-server
用于64位JVM。服务器JVM在删除无法执行任何操作的代码方面更为积极。例如空循环。无论计数限制如何,您都会发现这样的循环需要大约相同的时间,因为它取决于检测和消除循环所需的时间。尝试在同一个方法中添加第二个定时循环,你会发现无论你设置的最大值是什么,它几乎都没有时间(假设它不是一个无限循环)这是因为该方法将在第二个循环时编译启动。
http://docs.oracle.com/javase/1.5.0/docs/guide/vm/server-class.html
BTW:我会使用nanoTime并重复运行你的测试至少几秒钟。