首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何禁用编译器和JVM优化?

如何禁用编译器和JVM优化?
EN

Stack Overflow用户
提问于 2011-03-09 06:58:42
回答 3查看 14.1K关注 0票数 20

我有一个测试Calendar.getInstance().getTimeInMillis()System.currentTimeMilli()的代码:

代码语言:javascript
复制
long before = getTimeInMilli();
for (int i = 0; i < TIMES_TO_ITERATE; i++)
{
  long before1 = getTimeInMilli();
  doSomeReallyHardWork();
  long after1 = getTimeInMilli();
}
long after = getTimeInMilli();
System.out.println(getClass().getSimpleName() + " total is " + (after - before));

我希望确保没有发生JVM或编译器优化,因此测试将是有效的,并将实际显示不同之处。

如何确定?

编辑:我更改了代码示例,这样就更清晰了。我在这里要检查的是,在不同的实现中调用getTimeInMilli()需要多长时间-- CalendarSystem

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-03-09 07:04:40

我觉得你需要让JIT瘫痪。添加到您的run命令next选项:

代码语言:javascript
复制
-Djava.compiler=NONE
票数 36
EN

Stack Overflow用户

发布于 2011-03-09 07:06:55

您希望进行优化,因为它会在现实生活中发生--如果JVM没有按照您感兴趣的实际情况进行优化,那么测试就无效了。

但是,如果您想确保JVM不删除它可能会考虑不执行操作的调用,一个选项是使用结果--因此,如果您重复调用System.currentTimeMillis(),则可以将所有返回值和起来,然后在最后显示和。

注意,您可能仍然存在一些偏见--例如,如果JVM能够廉价地确定上次调用System.currentTimeMillis()只经过了一小段时间,那么可能会有一些优化,因此它可以使用缓存的值。我不是说这是真的,但这是你需要考虑的事情。最终,基准测试只能真正测试您给它们带来的负载。

另一件需要考虑的事情是:假设您想对代码大量运行的真实情况进行建模,那么在进行任何计时之前,您应该运行大量代码--因为Hotspot JVM将越来越难优化,而且您可能关心经过严重优化的版本,并且不希望度量JITting和代码的“缓慢”版本的时间。

正如斯蒂芬提到的,你几乎可以肯定的是,你应该把时间控制在循环之外.别忘了用结果..。

票数 11
EN

Stack Overflow用户

发布于 2011-03-09 07:34:51

您所做的工作看起来像是基准测试,您可以阅读健壮的Java基准测试以获得一些关于如何使其正确的良好背景。一句话,你不需要关掉它,因为它不会发生在生产服务器上。相反,您需要知道是否接近“实时”估计/性能。在优化之前,您需要“热身”您的代码,如下所示:

代码语言:javascript
复制
// warm up
for (int j = 0; j < 1000; j++) {
    for (int i = 0; i < TIMES_TO_ITERATE; i++)
    {
        long before1 = getTimeInMilli();
        doSomeReallyHardWork();
        long after1 = getTimeInMilli();
    }
}

// measure time
long before = getTimeInMilli();
for (int j = 0; j < 1000; j++) {
    for (int i = 0; i < TIMES_TO_ITERATE; i++)
    {
        long before1 = getTimeInMilli();
        doSomeReallyHardWork();
        long after1 = getTimeInMilli();
    }
}
long after = getTimeInMilli();

System.out.prinltn( "What to expect? " + (after - before)/1000 ); // average time

当我们使用这种方法度量代码的性能时,我们的代码需要工作的实时时间就会更少。更好的方法是用分离的方法度量代码:

代码语言:javascript
复制
public void doIt() {
    for (int i = 0; i < TIMES_TO_ITERATE; i++)
    {
        long before1 = getTimeInMilli();
        doSomeReallyHardWork();
        long after1 = getTimeInMilli();
    }
}

// warm up
for (int j = 0; j < 1000; j++) {
    doIt()
}

// measure time
long before = getTimeInMilli();
for (int j = 0; j < 1000; j++) {
    doIt();
}
long after = getTimeInMilli();

System.out.prinltn( "What to expect? " + (after - before)/1000 ); // average time

第二种方法更精确,但也取决于VM。例如,HotSpot可以执行“堆内替换”,这意味着如果方法的某些部分经常被执行,它将被VM优化,旧版本的代码将在执行方法时与优化版本进行交换。当然,它需要从VM端执行额外的操作。JRockit不这样做,只有在再次执行此方法时才会使用优化版本的代码(因此没有“运行时”优化.我是说,在我的第一个代码样本中,所有的旧代码都会被执行.除了doSomeReallyHardWork内部--它们不属于这个方法,所以优化将很好地工作)。

更新:相关代码是在我回答时编辑的;)

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

https://stackoverflow.com/questions/5242405

复制
相关文章

相似问题

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