2

Java 编译器是否足够聪明,可以优化下面的循环,通过提取

Double average = new Double( totalTime / callCount ); 

退出for循环?

public double computeSD( Set values, int callCount, long totalTime ) {
  double diffs = 0.0d; 
  for( Iterator i=values.iterator(); i.hasNext(); ) {
    double value = ( ( Double )i.next() ).doubleValue(); 
    Double average = new Double( totalTime / callCount ); 
    diffs += ( value – average.doubleValue() ) * ( value – average.doubleValue() );
  } 
  double variance = diffs / callCount;
  return Math.sqrt( variance );
}
4

5 回答 5

4

没有什么能阻止字节码编译器(java->bytecode)执行优化。当我在赛门铁克工作时,他们做了一个 Java IDE,编译器编写者确实考虑在我们的编译器中进行一些优化,但表示(在外界)似乎没有人感兴趣,重点是即时 (JIT)编译器与现代 Sun VM 中的 HotSpot 大致相同。

没有什么可以阻止字节码编译器执行优化,但我不知道有什么这样做的。人们非常关注运行时优化,但这些在运行时几乎是隐藏的。

因此,source->bytecode 编译器可能不会优化它,但 VM 可能会。如果您使用的是 Android 之类的设备,那么它可能不会执行运行时优化。

于 2010-03-06T03:55:29.977 回答
4

Java 不会也不能从循环中提取它。任何使用“new”关键字都会导致创建一个新对象。你最好使用Double.valueOf()

请参阅 javadoc Double.valueOf(double)

"返回一个表示指定 double 值的 Double 实例。如果不需要新的 Double 实例,则通常应优先使用此方法而不是构造函数 Double(double),因为此方法可能会通过以下方式产生显着更好的空间和时间性能缓存经常请求的值。”

如果您使用此方法,它将每次返回相同的对象,从而减少创建的对象数量并提高性能。

但是,使用valueOf仍然不是您的答案!

valueOf仍然是一个方法调用,并且方法调用没有得到优化。它将调用valueOf循环的每次迭代。查看您的方法并计算方法调用。现在是 6,包括hasNextand new Double,类似于方法调用。这些都会每次都发生,并且没有 java 优化会改变这一点。您最好重构以从循环中删除尽可能多的方法调用。

于 2012-09-24T20:27:59.830 回答
2

如果您真的想确定,这个问题的答案会告诉您如何查看 JIT 编译器生成的本机代码。

于 2010-03-06T03:46:52.897 回答
2

乍一看,这似乎是一个明显的优化,但我不这么认为,因为它涉及对象实例化。诚然,它是一个不可变的原始盒子类型的实例化,但这仍然不能保证没有副作用。

我认为当前的任何编译器都无法对此进行优化。要对此进行优化,必须告知编译器某些类具有特殊属性(考虑到将来情况可能会发生变化,这可能是一个危险的提议)。也就是说,编译器必须被告知 API 的细节。这不能仅在语言级别进行优化。

但是,如果您使用double,它更有可能被优化(例如,使用循环不变代码运动技术)。

于 2010-03-06T03:26:58.620 回答
0

并不真地。编译器只是写出byte-code。如果对代码进行了优化,那就是 Java 虚拟机,这可能取决于平台、实现和执行条件......

于 2010-03-06T03:21:06.897 回答