为什么即使代码缓存已满,代码缓存也没有刷新?

问题描述 投票:0回答:1

当我们从 Java 17 切换到 Java 21 时,我们的缓存行为方式发生了变化。

我们有运行串行 GC 收集器(由 JVM 选择)的小型服务,通常是大约 400 MB 的堆和大约 40 MB 的非分段代码缓存,我想这在今天的标准中是很低的。

以下是我们通常使用的已配置 JVM 选项。

java
-Xmx400m
-Xss256k
-XX:MaxMetaspaceSize=120m
-XX:MaxDirectMemorySize=64m
-XX:CompressedClassSpaceSize=10m
-Xlog:gc*=info,codecache*=info // for debugging 
-XX:ReservedCodeCacheSize=40m
-XX:MinHeapFreeRatio=50
-XX:MaxHeapFreeRatio=50
-XX:+HeapDumpOnOutOfMemoryError
-XX:-ShrinkHeapInSteps
-XX:MaxGCPauseMillis=10

在 Java 17 中,代码缓存通常会经常被垃圾收集。现在,如果一个服务不需要执行完整的GC(我看到tenured/old的堆占用率非常低),则代码缓存永远不会被刷新。代码缓存刷新似乎是完整 GC 周期的一部分。

真正奇怪的是,即使代码缓存被填满,它也不会执行任何积极的扫描,即使我将 StartAggressiveSweepingAt 设置为一个很高的数字。我尝试添加以下内容来在分配时触发代码缓存 GC,但没有任何运气。

 -XX:SweeperThresholdStartAggressiveSweepingAt=20
 -XX:SweeperThreshold=0.5
 -XX:NmethodSweepActivity=500

问题是,当服务启动时,我确实进行了一些代码缓存扫描,因此启用了“功能”。它会进行一些扫描,但这是包含短语“代码缓存”的 GC 日志的最后一次出现。观察日志中的“由于分配 2.135% 导致触发阈值 (2.125%) GC”。

[1891.824s][info][gc ] GC(125) Pause Young (Allocation Failure) 125M->69M(202M) 3.616ms
[1891.824s][info][gc,cpu ] GC(125) User=0.00s Sys=0.00s Real=0.00s
[1891.824s][info][gc,heap ] GC(125) Tenured: 71312K(142628K)->71312K(142628K)
[1938.484s][info][codecache ] Triggering threshold (2.125%) GC due to allocating 2.135% since last unloading (44.729% used -> 46.864% used)
[1938.485s][info][gc,start ] GC(126) Pause Young (GCLocker Initiated GC)
[1938.489s][info][gc,cpu ] GC(126) User=0.00s Sys=0.00s Real=0.01s
[1938.488s][info][gc,heap ] GC(126) DefNew: 44957K(64320K)->923K(64320K) Eden: 44605K(57216K)->0K(57216K) From: 351K(7104K)->923K(7104K)
[1938.489s][info][gc ] GC(126) Pause Young (GCLocker Initiated GC) 113M->70M(202M) 3.711ms
[1938.489s][info][gc,heap ] GC(126) Tenured: 71312K(142628K)->71312K(142628K)
[1938.489s][info][gc,metaspace ] GC(126) Metaspace: 92917K(93504K)->92917K(93504K) NonClass: 81847K(82176K)->81847K(82176K) Class: 11069K(11328K)->11069K(11328K)
[1994.918s][info][gc,start ] GC(127) Pause Young (Allocation Failure)

对我来说,听起来此时应该触发 GC(Full),但它并没有发生。几个小时没有完整的 GC。我查看了 JDK 的源代码,预计会安排完整的 GC。 https://github.com/openjdk/jdk/blob/369bbecc0dab389b523c09bc332fe1cf6394cb26/src/hotspot/share/code/codeCache.cpp#L799-L804

我还发现了这个https://bugs.openjdk.org/browse/JDK-8290025我认为这是行为变化的原因。

所以我的问题是,为什么当代码缓存被填满时没有触发full GC?我应该尝试什么参数?仅在完全GC时清除,由其他原因调用。

java jvm-hotspot jvm-arguments openjdk-21 jvm-codecache
1个回答
0
投票

我的情况也有同样的问题。它是分段 CodeCache:非配置文件 nmethods 的一部分。迁移到 Java 21 后开始。

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.