4

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

我还观察到代码缓存也在缓慢上升。所以我决定将 Code Cache 预留提高到 500MB 进行测试。坏动作!现在它花费更多的时间来执行 JIT。

然后我通过-XX:-UseCodeCacheFlushing. 但是,我注意到峰值代码缓存使用量大于当前大小。这让我想到了几个问题:

在此处输入图像描述

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

1 回答 1

2

在 HotSpot JVM 中,所有 JIT 编译的方法都保留在 CodeCache 中,直到它们被回收。UseCodeCacheFlushing影响冷(但仍然有效)编译方法的回收。但是,CodeCache 也可能包含过时或无效的方法(“僵尸”),即使使用-XX:-UseCodeCacheFlushing.

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

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

于 2018-07-13T11:19:22.677 回答