Oracle JVM 8:启用 Codecache 刷新时,刷新了多少?
Oracle JVM 8: when Codecache flushing is enabled, how much is flushed?
我是 运行 Oracle Java 8 JVM(服务器,不是客户端或嵌入式),启用了 ReservedCodeCacheSize=128M 和 UseCodeCacheFlushing。几天后,Codecache 从 93% 快速下降到 80%。我假设我目睹了 Codecache 刷新,但令人惊讶的是 post-刷新大小接近 100% 满而不是 50% 满。
JVM 如何决定要刷新多少 Codecache?
This Oracle Java 8 page 描述了选项但没有量化刷新的 Codecache:
Enables flushing of the code cache before shutting down the compiler. This option is enabled by default. To disable flushing of the code cache before shutting down the compiler, specify -XX:-UseCodeCacheFlushing.
There is a JVM option UseCodeCacheFlushing that can be used to control the flushing of the Codecache. With this option enabled JVM invokes an emergency flushing that discards older half of the compiled code(nmethods) to make space available in the CodeCache.
可想而知,老半段编译后的代码只占整个Codecache的20%,但另一种可能的解释是,上面的博客post是不准确的。
'Older half'并不是字面意思是所有nmethods的50%。 HotSpot扫码编译逻辑有点复杂;最好的解释是source code,但我会在下面做一个简短的总结。
如果至少满足以下条件之一,则会调用清扫程序:
- 代码缓存快满了。
- 自上次扫描以来状态发生了足够多的变化(JDK 8 次测量 'enough' 超过
ReservedCodeCacheSize
的 1%。
- 自上次扫描以来已经过了一定的时间间隔。 Code Cache 中可用的 space 越多,清除程序的调用频率就越低。确切的公式是 here.
当清理器 运行s 时,它总是释放所有 zombie nm 方法,即没有激活的卸载、去优化或重新编译的方法。
此外,如果启用 UseCodeCacheFlushing
,它会释放 alive 足够 cold 的方法。冷法判定如下:
- 在每个安全点,具有活动堆栈帧的 nmethods 的 热度计数器 重置为默认值。默认热度值为
2 * (ReservedCodeCacheSize / 1MB)
.
- 清扫器每次 运行 都会将 alive 方法的热度计数器减 1。
- 如果热度计数器小于计算的阈值,则释放 nmethod。阈值取决于代码缓存空闲比率和
-XX:NmethodSweepActivity
选项(默认为 10)。 NmethodSweepActivity
越大,Code Cache free ratio 越小,编译后的方法被清除得越积极。 Here是公式。
因此,没有确切的数字扫描了多少编译方法。这是在 运行 时间内计算的,具体取决于保留的代码缓存大小、可用量 space、僵尸方法的数量、冷方法的数量和 JIT 人体工程学选项,如 [=14] =].
我是 运行 Oracle Java 8 JVM(服务器,不是客户端或嵌入式),启用了 ReservedCodeCacheSize=128M 和 UseCodeCacheFlushing。几天后,Codecache 从 93% 快速下降到 80%。我假设我目睹了 Codecache 刷新,但令人惊讶的是 post-刷新大小接近 100% 满而不是 50% 满。
JVM 如何决定要刷新多少 Codecache?
This Oracle Java 8 page 描述了选项但没有量化刷新的 Codecache:
Enables flushing of the code cache before shutting down the compiler. This option is enabled by default. To disable flushing of the code cache before shutting down the compiler, specify -XX:-UseCodeCacheFlushing.
There is a JVM option UseCodeCacheFlushing that can be used to control the flushing of the Codecache. With this option enabled JVM invokes an emergency flushing that discards older half of the compiled code(nmethods) to make space available in the CodeCache.
可想而知,老半段编译后的代码只占整个Codecache的20%,但另一种可能的解释是,上面的博客post是不准确的。
'Older half'并不是字面意思是所有nmethods的50%。 HotSpot扫码编译逻辑有点复杂;最好的解释是source code,但我会在下面做一个简短的总结。
如果至少满足以下条件之一,则会调用清扫程序:
- 代码缓存快满了。
- 自上次扫描以来状态发生了足够多的变化(JDK 8 次测量 'enough' 超过
ReservedCodeCacheSize
的 1%。 - 自上次扫描以来已经过了一定的时间间隔。 Code Cache 中可用的 space 越多,清除程序的调用频率就越低。确切的公式是 here.
当清理器 运行s 时,它总是释放所有 zombie nm 方法,即没有激活的卸载、去优化或重新编译的方法。
此外,如果启用 UseCodeCacheFlushing
,它会释放 alive 足够 cold 的方法。冷法判定如下:
- 在每个安全点,具有活动堆栈帧的 nmethods 的 热度计数器 重置为默认值。默认热度值为
2 * (ReservedCodeCacheSize / 1MB)
. - 清扫器每次 运行 都会将 alive 方法的热度计数器减 1。
- 如果热度计数器小于计算的阈值,则释放 nmethod。阈值取决于代码缓存空闲比率和
-XX:NmethodSweepActivity
选项(默认为 10)。NmethodSweepActivity
越大,Code Cache free ratio 越小,编译后的方法被清除得越积极。 Here是公式。
因此,没有确切的数字扫描了多少编译方法。这是在 运行 时间内计算的,具体取决于保留的代码缓存大小、可用量 space、僵尸方法的数量、冷方法的数量和 JIT 人体工程学选项,如 [=14] =].