【问题标题】:Java: Strange runtime behaviour in mainJava:main中的奇怪运行时行为
【发布时间】:2012-11-28 23:22:12
【问题描述】:

我在以下代码中遇到了(对我而言)奇怪的运行时行为:

public class Main{

    private final static long ROUNDS = 1000000;
    private final static double INITIAL_NUMBER = 0.45781929d;
    private final static double DIFFERENCE = 0.1250120303d;


    public static void main(String[] args){

        doSomething();
        doSomething();
        doSomething();
    }


    private static void doSomething(){

        long begin, end;
        double numberToConvert, difference;


        numberToConvert = INITIAL_NUMBER;
        difference = DIFFERENCE;

        begin = System.currentTimeMillis();

        for(long i=0; i<ROUNDS; i++){

            String s = "" + numberToConvert;

            if(i % 2 == 0){
                numberToConvert += difference;
            }
            else{
                numberToConvert -= difference;
            }
        }

        end = System.currentTimeMillis();

        System.out.println("String appending conversion took " + (end - begin) + "ms.");
    }
}

我希望程序每次都能打印出类似的运行时。但是,我得到的输出总是这样:

String appending conversion took 473ms.
String appending conversion took 362ms.
String appending conversion took 341ms.

第一次调用比之后的调用慢约 30%。大多数时候,第二次调用也比第三次调用稍慢。

java/javac 版本:

javac 1.7.0_09 java version "1.7.0_09" OpenJDK Runtime Environment (IcedTea7 2.3.3) (7u9-2.3.3-0ubuntu1~12.04.1) OpenJDK 64-Bit Server VM (build 23.2-b09, mixed mode)

那么,我的问题是:为什么会发生这种情况?

【问题讨论】:

  • 我会将“String s”放在循环之外,然后使用“s = Integer.toString(numberToConvert);”分配值.这可能会提高性能,因为它不会每次都创建新的 String 对象。
  • @jlordo - 是的,但是您编写它的方式,它创建了 2+ 个字符串对象。按照我的建议,只有 1 个字符串对象用作参考。
  • @jlordo 该代码最初指定用于比较 "" + 和 PrimitiveWrapper.toString() 和 String.valueOf() 的运行时。那就是我遇到上述问题的地方。我只是从源代码中删除了其他两种方法,以进一步研究这个特殊问题。无论如何感谢您的提示。 :)
  • @djangofan +1 我的错。我读得不够准确。您指的是"" + int 部分,我只是指循环部分之外的move String s;
  • @jlordo - 好的。好吧,如果您真的仔细检查了代码,您也可以找到导致性能差异的其他原因。我敢打赌,如果你足够努力,你会找出罪魁祸首。

标签: java runtime behavior


【解决方案1】:

即时 (JIT) 编译器正在动态分析您的代码并优化执行。一段代码执行得越频繁,它的优化就越好。

例如,请参阅此问题以获取更多信息:(How) does the Java JIT compiler optimize my code?

【讨论】:

  • 第一次迭代的缓存未命中和页面错误也可能比第二次或后续迭代更多。
  • @Dmitry Beransky:谢谢!按照并阅读您的链接,我发现 JIT 编译器(我认为热点是它的名称)是导致这种行为的原因。我找到了更多信息here。因此,我使用-Xint option 测试了代码,只是为了发现所有调用消耗的时间大致相同。谢谢!
【解决方案2】:

您正在运行的其他应用程序可能会影响您分配给机器上 JVM 的内存量。尝试在运行 java 命令时为 JVM 设置相同的最小和最大内存:

java -Xms512M -Xmx512M ...

尝试运行它时,我得到了相当一致的间隔:

String appending conversion took 1153ms.
String appending conversion took 1095ms.
String appending conversion took 1081ms.

【讨论】:

  • 试过了,结果没有变化。
猜你喜欢
  • 1970-01-01
  • 2011-10-07
  • 2021-02-23
  • 2015-03-21
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
相关资源
最近更新 更多