如何确定Hotspot JVM决定再次重新编译JIT:ed代码的原因?

use*_*744 15 java jit jvm-hotspot jvm-arguments

我正在尝试为延迟敏感的Java应用程序编写一个预热例程,以便优化前几个可能因动态类加载和JIT(主要是)而减慢的事务.

我面临的问题是,即使我的预热代码加载所有类并通过多次调用它们(至少100次-XX:CompileThreshold)来练习它们,之后当实际用户登录这些相同的函数时仍然标记为"非参赛者"并再次重新编译,这会造成延迟.

JVM标志如下(我只添加了-XX:+ PrintCompilation -verbose:class tp troubleshoot,其他是遗留的):

-Xms5g -Xmx5g -server -XX:+ AggressiveHeap -XX:+ UseFastAccessorMethods -XX:+ PrintGCDetails -XX:CompileThreshold = 100 -XX:-CITime -XX:-PrintGC -XX:-PrintGCTimeStamps -XX:+ PrintCompilation -verbose:类

#Warmup happens here
  12893 2351       my.test.application.hotSpot (355 bytes)
#Real user logs on here
 149755 2351      made not entrant  my.test.application.hotSpot (355 bytes)
 151913 2837       my.test.application.hotSpot (355 bytes)
 152079 2351      made zombie  my.test.application.hotSpot (355 bytes)
Run Code Online (Sandbox Code Playgroud)

在预热之后没有发生类加载(我之前可以看到类加载,因此标志正在工作).

看起来该函数获得了一个新的ID(2351 vs 2837),这意味着它被JVM视为"不同".

我如何确定JVM决定重新编译此函数的原因?

我想这归结为我如何确定ID改变的原因?标准是什么?

我尝试尽可能多地标记尽可能多的方法和类,但无济于事.

这是JRE 1.6.0_45-b06.

有关如何排除故障或获取更多信息的任何提示!:)

use*_*744 13

对于后代,一旦我阅读了热点JVM的一些源代码,它就相当简单了.

以下标志将指出导致函数被去优化和重新编译的确切源代码行:

-XX:+TraceDeoptimization -XX:+WizardMode -XX:+PrintNativeNMethods -XX:+PrintDependencies -XX:+DebugDeoptimization -XX:+LogEvents
Run Code Online (Sandbox Code Playgroud)

通常这是一个if语句.

void function (Object object){
    if ( object == null ){
        // do some uncommon cleanup or initialization
    }
    do_stuff();
}
Run Code Online (Sandbox Code Playgroud)

假设我的热身代码从未触发过if语句.

我假设整个函数将一次编译,但是,当JIT C2编译器实际上决定为此函数生成本机代码时,它不会为if语句生成任何代码,因为该代码路径从未被拍摄.

它只会生成一个条件分支,在C2编译器线程中生成陷阱和异常处理程序.我认为这是因为本机代码缓存非常小,因此JVM编写器不希望用可能无用的代码填充它.

无论如何,如果该语句永远为真(即对象永远为空),则该函数将立即无条件地触发此异常处理并重新编译(导致冻结/延迟命中大约几毫秒).

当然,我的热身代码不会以与生产完全相同的方式调用每个函数,我冒昧地猜测,在任何复杂的产品中,这几乎是不可能的,而且无论如何都是维护噩梦.

这意味着为了有效地预热java应用程序,代码中的每个if语句都需要通过预热代码调用.

所以我们只是放弃了"热身"我们的java代码的想法,因为它并不像有些人想象的那么简单.

由于以下原因,我们将重新编写部分应用程序,以支持每次运行数周/数月:

  • 维护更简单(我们不需要在预热期间模拟生产并保持更新)
  • JIT不会根据我们的塑料模拟来完成,而是根据生产行为(即使用JIT来实现它的设计而非对抗它)

长期来看,客户可能需要为C/C++等重写付费,以获得始终如一的低延迟,但这是另一天.

编辑:让我只是添加更新到热点JVM的新版本或围绕热点JVM参数"调整"永远不会解决此问题.它们都是烟雾和镜子.事实是热点JVM从来没有为可预测的低延迟编写,这个缺点是不可能在java用户区内解决的.

  • 这是不正确的.没有"根本性的缺陷".只有这个特定的JVM不是为可预测的低延迟而设计的(而提供这种功能的专用JVM通常很昂贵).但主要问题似乎是你专注于去优化事件而不是你声明的目标.如果你想要*可预测*延迟,你可以简单地关闭JIT编译器.但我宁愿专注于*低延迟*,通过将最新的JVM与最新的硬件相结合,以获得低于所需阈值的*最坏情况*. (3认同)
  • @Holger即使您使用了HotSpot的开发树,它也永远不会为软实时程序创造一个合适的环境 - 它从未被设计为这样做.如果你需要软实时约束,你想要使用那些设计时考虑到这些事情的东西,特别是GC.有些JVM正是这样做的,所以我不完全确定为什么有人会想用HotSpot来实现这一目标......显然整个事情与java语言没有任何关系. (2认同)