首页
学习
活动
专区
圈层
工具
发布

Java效率
EN

Stack Overflow用户
提问于 2012-01-20 03:03:17
回答 6查看 1.1K关注 0票数 12

我正在使用一些代码,计算计算一些Java代码所需的时间,以获得一些Java功能的效率或低效的感觉。这样做,我现在陷入了一些非常奇怪的效果,我只是不能解释我自己。也许你们中有人能帮我理解一下。

代码语言:javascript
复制
public class PerformanceCheck {

 public static void main(String[] args) {
    List<PerformanceCheck> removeList = new LinkedList<PerformanceCheck>();

    int maxTimes = 1000000000;

    for (int i=0;i<10;i++) {
        long time = System.currentTimeMillis();

        for (int times=0;times<maxTimes;times++) {
            // PERFORMANCE CHECK BLOCK START

            if (removeList.size() > 0) {
                testFunc(3);
            }

            // PERFORMANCE CHECK BLOCK END
        }

        long timeNow = System.currentTimeMillis();
        System.out.println("time: " + (timeNow - time));
    }
 }

 private static boolean testFunc(int test) {
    return 5 > test;
 }

}

开始执行此操作将导致相对较长的计算时间(请记住,removeList为空,因此甚至不调用testFunc ):

代码语言:javascript
复制
time: 2328
time: 2223
...

而将removeList.size() >0和testFunc(3)的任何组合替换为其他任何组合都会得到更好的结果。例如:

代码语言:javascript
复制
...
if (removeList.size() == 0) {
    testFunc(3);
}
...

结果(每次都会调用testFunc):

代码语言:javascript
复制
time: 8
time: 7
time: 0
time: 0

即使相互独立地调用这两个函数,也会导致较短的计算时间:

代码语言:javascript
复制
...
if (removeList.size() == 0);
    testFunc(3);
...

结果:

代码语言:javascript
复制
time: 6
time: 5
time: 0
time: 0
...

在我的初始示例中,只有这种特殊的组合才需要这么长时间。这让我很恼火,我真的很想理解它。它有什么特别之处?

谢谢。

添加:

更改第一个示例中的testFunc()

代码语言:javascript
复制
if (removeList.size() > 0) {
                testFunc(times);
}

到其他东西,比如

代码语言:javascript
复制
private static int testFunc2(int test) {
    return 5*test;
}

将导致再次变得更快。

EN

回答 6

Stack Overflow用户

发布于 2012-01-20 03:16:37

这真的很令人惊讶。生成的字节码除了条件之外是相同的,即ifleifne

如果您使用-Xint关闭JIT,结果会更加合理。第二个版本要慢2倍。所以这与JIT优化有关。

我假设它可以在第二种情况下优化检查,但不能优化第一种情况(无论是什么原因)。尽管这意味着它完成了函数的工作,但缺少这个条件会让事情变得更快。它避免了管道停滞之类的问题。

票数 3
EN

Stack Overflow用户

发布于 2012-01-20 05:00:02

虽然与这个问题没有直接关系,但这就是如何使用Caliper正确地对代码进行微基准测试。下面是您的代码的修改版本,以便它可以与Caliper一起运行。内部循环必须进行一些修改,以便VM不会优化它们。在意识到什么都没有发生时,它出人意料地聪明。

在对Java代码进行基准测试时,也有许多细微差别。我写了一些我在Java Matrix Benchmark遇到的问题,比如过去的历史如何影响现在的结果。通过使用Caliper,您可以避免许多这样的问题。

  1. http://code.google.com/p/caliper/
  2. Benchmarking issues with Java Matrix Benchmark

公共类PerformanceCheck扩展了SimpleBenchmark { public int timeFirstCase(int reps) { List removeList =新的LinkedList();removeList.add(新的PerformanceCheck());int ret = 0;for( int i= 0;i< reps;i++ ){ if ( removeList.size() > 0) { if ( testFunc(i) ) ret++;}} return ret;} public int reps( int reps) {timeSecondCase removeList = LinkedList();removeList.add( new PerformanceCheck());int ret = 0;for( int i= 0;i< reps;i++ ){ if ( removeList.size() == 0) { if ( testFunc(i) ) ret++;}} return ret;}私有静态布尔测试(Int TestFunc){ return 5>测试;}公共静态空main(String[] args) { Runner.main(PerformanceCheck.class,args);} }

输出:

代码语言:javascript
复制
 0% Scenario{vm=java, trial=0, benchmark=FirstCase} 0.60 ns; σ=0.00 ns @ 3 trials
50% Scenario{vm=java, trial=0, benchmark=SecondCase} 1.92 ns; σ=0.22 ns @ 10 trials

 benchmark    ns linear runtime
 FirstCase 0.598 =========
SecondCase 1.925 ==============================

vm: java
trial: 0
票数 2
EN

Stack Overflow用户

发布于 2012-01-20 03:59:06

嗯,我很高兴不必处理Java性能优化。我自己在64位Java JDK 7中尝试过。结果是任意的;)。无论我使用的是哪个列表,或者是否在进入循环之前缓存size()的结果,都没有区别。此外,完全清除测试函数几乎没有区别(因此它也不能成为分支预测命中)。优化标志可以提高性能,但也是任意的。

这里唯一的逻辑结果是,JIT编译器有时能够优化掉语句(这并不是很难实现),但它似乎相当武断。我更喜欢像C++这样的语言的众多原因之一,在这些语言中,行为至少是确定性的,即使它有时是任意的。

顺便说一句,在最新的Eclipse中,就像它一直在Windows上一样,通过IDE "Run“(无调试)运行这段代码比从控制台运行它慢10倍,所以关于这一点……

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8931754

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档