Java JVM编译时与代码缓存

Java JVM编译时与代码缓存,java,jvm,jit,jvm-codecache,Java,Jvm,Jit,Jvm Codecache,我一直在对我的应用程序进行基准测试,并与JMC进行分析。我注意到,在加载时,它会执行相当多的JIT编译。如果我每秒发送大量事务,编译时间就会出现峰值。编译时间总是随着针对应用程序的任何重载测试而成比例增长 我还观察到代码缓存也在缓慢上升。所以我决定将代码缓存保留空间提高到500MB以进行测试。糟糕的举动!现在,它将花费更多的时间执行JIT 然后,我通过-XX:-UseCodeCacheFlushing显式禁用了代码缓存刷新。但是,我注意到峰值代码缓存使用量大于当前大小。这就引出了几个问题: J

我一直在对我的应用程序进行基准测试,并与JMC进行分析。我注意到,在加载时,它会执行相当多的JIT编译。如果我每秒发送大量事务,编译时间就会出现峰值。编译时间总是随着针对应用程序的任何重载测试而成比例增长

我还观察到代码缓存也在缓慢上升。所以我决定将代码缓存保留空间提高到500MB以进行测试。糟糕的举动!现在,它将花费更多的时间执行JIT

然后,我通过
-XX:-UseCodeCacheFlushing
显式禁用了代码缓存刷新。但是,我注意到峰值代码缓存使用量大于当前大小。这就引出了几个问题:

  • JVM是否尝试缓存每个JIT编译
  • 为什么即使我禁用了刷新,峰值代码缓存大小仍大于当前大小
  • 是否存在在函数结束后自动删除的“临时”编译代码

  • 在HotSpot JVM中,所有JIT编译的方法都保留在CodeCache中,直到它们被回收
    useCodeCache
    影响冷(但仍然有效)编译方法的回收。但是,CodeCache也可能包含过时或无效的方法(“僵尸”),即使使用
    -XX:-UseCodeCacheFlushing
    ,这些方法也会在下一个扫描周期中被清除

    • 在一种模式下(自JDK 8以来的默认值),可以使用不同的优化级别多次编译一个方法。一旦安装了方法的优化(第4层)版本,以前的版本就会过时,并且可以在该版本的所有激活完成后回收
    • 当推测失败时(例如,在加载新类之后),推测编译的方法可能会变得无效。这种方法也会变成僵尸,以后可以回收
    • 另一个例子是。这是专门编译的方法的一个版本,用于在方法运行时将执行从解释器转移到编译代码。回答您的第三个问题,这是一种“临时”方法,在安装完整版本的编译方法并完成所有OSR激活后,它就会过时

    有一个单独的JVM标志
    -XX:-MethodFlushing
    ,以防止彻底清除CodeCache,包括僵尸方法。

    感谢您的详细解释。您知道即使整个方法太大而无法编译,OSR编译是否也会运行吗?因此,只有部分方法通过OSR编译,然后在完成时刷新?@StanislavPalanik限制对于OSR和非OSR编译基本相同。但上限足够大(8000字节码),在实际应用中不会成为问题。