尝试重复处理相同的信息时,java是否“作弊”

时间:2015-12-01 00:34:09

标签: java

我正在尝试分析一些方法,以了解哪些实现更快。我遇到了一个障碍,因为java似乎是在每次请求时不处理所有信息而欺骗配置文件。

public void Profile() {
    double[] testArray = new double[100000000];
    Math math = new Math();
    long start = System.nanoTime();
    for (int i = 1; i <= 100000000; i++) {
        testArray[i - 1] = math.Divide(i);
    }
    long stop = System.nanoTime();
    System.out.println("math.divide(): " + TimeUnit.NANOSECONDS.toMillis(stop - start));
    System.out.println(testArray[(int) (java.lang.Math.random() * (100000000 - 0))]);
}

public class Math {
    public double Divide(int i) {
        int dividend = i;
        int divisor = 12;
        return dividend / (double) divisor;
    }
}

如果我没有将Math.Divide()值赋给数组,则整个for循环在2 ms内返回,当我这样做时,它返回~200 ms,这仍然看起来太快(考虑相同在C#中实现至少需要1.8秒。

最终我的问题是:是否有更准确的方法来分析方法?我如何覆盖java,以便它停止跳过它认为多余的工作。

3 个答案:

答案 0 :(得分:1)

正如评论中已经提到的,这根本就没有作弊。这是JVM的一个特性,该功能称为JIT。在其他优化中,它将执行可见性检查,如果执行您从未使用过的操作,它将完全避免运行代码。就像你的第一个例子一样。

换句话说:这不是一个错误,这是一个功能。一个真正的特色。

如果您想正确地进行微基准测试,请使用JMH。 Here是一个显示示例代码的链接,并注意有多少示例可以“解决”JVM否则将执行的各种优化,以便基准环境保持稳定:JVM(至少是HotSpot)非常,非常擅长优化。

答案 1 :(得分:0)

我在1980年代早期第一次遇到了Fortran基准测试优化的问题,但我并没有觉得这是一个新问题。

有两种解决方案。

最可靠的一个是对您真正关心的代码进行基准测试,如果语言实现有一种聪明的方法可以让它更快,那么您将会感到高兴。据推测,您正在编写除法函数,因为您关心某些程序中的整数除法性能。运行该程序作为您的基准。这样做的划分恰好与您相关的上下文,允许相关的优化,但没有相关的优化。

第二个最好的方法是真正地,非常谨慎地防止优化,阻止您测量的代码以您想要的方式运行。我的基本策略是确保我想测量的每一步最终都会影响人类可读显示器中的值。我不相信你的随机技巧,因为在内联除法函数之后,一个足够聪明的JVM可能会注意到只会显示一个除法结果,并且只是在翻转随机数生成器后计算出一个除法结果。相反,我会输出,例如,所有数组元素的异或。 @fge's answer中描述的JMH看起来是一种更好,更自动的方式。

答案 2 :(得分:0)

此优化用于克服解码指令两次的固有问题(类文件到jvm,jvm到cpu)。 JIT is described here...

我可以禁用JIT我告诉过,虽然我从来没有尝试过,这个论坛讨论了它: Oracle: Disabling JIT

  

JIT编译器可以从优化字节码的代码中获取错误。在将字节码转换为最佳二进制代码的阶段,您   有机会遇到一些意想不到的行为,你就得到了JVM   crahsed。

     

在这种情况下,您应该禁用某些特定的JIT编译   方法或整个JVM。 “-Xint”选项强制运行整个JVM   翻译模式。编译器命令文件(.hotspot_compiler文件)   提供“exclude”命令以禁用特定的JIT编译   方法。 exclude java / util / Arrays mergeSort

出于好奇,很遗憾对你推行计算机科学101,但你先计算过大O吗?