为了账号安全,请及时绑定邮箱和手机立即绑定

如何确定我使用哪种 GC?

如何确定我使用哪种 GC?

慕容708150 2022-07-06 19:14:24
我没有指定任何 GC,我认为我的 JVM 默认没有启用任何 GC。当然我知道OpenJDK8默认使用ParallelGC,但我认为它应该可以通过命令行打印,像这样:java -XX:+PrintFlagsFinal|grep Use|grep GC我希望输出包含 bool UseParallelOldGC = true {product}但它不是:     bool ParGCUseLocalOverflow                     = false                               {product}     bool UseAdaptiveGCBoundary                     = false                               {product}     bool UseAdaptiveSizeDecayMajorGCCost           = true                                {product}     bool UseAdaptiveSizePolicyWithSystemGC         = false                               {product}     bool UseAutoGCSelectPolicy                     = false                               {product}     bool UseConcMarkSweepGC                        = false                               {product}     bool UseDynamicNumberOfGCThreads               = false                               {product}     bool UseG1GC                                   = false                               {product}     bool UseGCLogFileRotation                      = false                               {product}和java -XX:+PrintCommandLineFlags -version我希望输出包含:XX:+UseParallelGC但也不是:-XX:InitialHeapSize=460493056 -XX:MaxHeapSize=7367888896 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops .我的 JVM 选项:-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -verbose:gc -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime.上面的输出表明没有启用任何 GC(我想是这样),我对这种情况感到非常困惑。日志显示 JVM 堆分为new和tenured,但没有打印 GC 类型。可悲的是,我也不能jmap -heap {pid}用来获取 GC 类型,因为 jmap 在我的环境中没有这个选项(-heap)。所以我想知道:哪个 GC 是我真正使用的?命令行选项(-XX:+PrintCommandLineFlags和-XX:+PrintFlagsFinal)输出信息是否正确?我的环境:k8s+docker,Alpine OpenJKD8
查看完整描述

2 回答

?
哔哔one

TA贡献1854条经验 获得超8个赞

jcmd <pid> VM.flags应该有帮助。


例如


$ /usr/java/jdk1.8.0_202/bin/java Test

...

$ jcmd 28815 VM.flags

28815:

-XX:CICompilerCount=3 -XX:InitialHeapSize=266338304 -XX:MaxHeapSize=4257218560 -XX:MaxNewSize=1418723328 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=88604672 -XX:OldSize=177733632 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC

最后打印的标志-XX:+UseParallelGC即使没有明确指定。


然后,如果我运行将 G1 作为默认收集器的 JDK 11,我将得到以下输出:


$ /usr/java/jdk11.0.2/bin/java Test

...

$ jcmd 28862 VM.flags

28862:

-XX:CICompilerCount=3 -XX:ConcGCThreads=1 -XX:G1ConcRefinementThreads=4 -XX:G1HeapRegionSize=1048576 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=266338304 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=4257218560 -XX:MaxNewSize=2554331136 -XX:MinHeapDeltaBytes=1048576 -XX:NonNMethodCodeHeapSize=5830092 -XX:NonProfiledCodeHeapSize=122914074 -XX:ProfiledCodeHeapSize=122914074 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC

现在最后打印的选项是-XX:+UseG1GC.


如果由于某种原因你没有jcmd可用的,你可以尝试jattach哪个是轻量级的独立替代品jcmd:


$ jattach 28862 jcmd VM.flags

更新


如果没有-XX:Use*GC打印任何标志,则表示使用了 Serial GC。这只发生在 JDK 8 和更早版本上。从 JDK 9 开始,Use*GCJVM 会自动设置其中一个标志。有关详细信息,请参阅JDK-8068582。


查看完整回答
反对 回复 2022-07-06
?
Helenr

TA贡献1780条经验 获得超4个赞

bool问题是,当您真正想要一个名称时,您正在查看类型的 JVM 选项。这不是你的错,JVM 的设计者决定给不同的垃圾收集器命名,但提供看起来像布尔选项的控件。


因此,即使所有这些选项都是false,也有一个垃圾收集器,但这些选项不足以获得它的名字。但另一方面,无论如何,大多数名称都不足以描述这些垃圾收集器的作用,或者它们与其他算法的不同之处。


JDK8默认使用ParallelGC并不完全正确;正如这个答案所描述的,该算法是由一些启发式选择的,但是,在大多数情况下,你最终会选择 ParallelGC。


使用以下代码


Object flags = ManagementFactory.getPlatformMBeanServer().invoke(

    ObjectName.getInstance("com.sun.management:type=DiagnosticCommand"),

    "vmFlags", new Object[] { null }, new String[] { "[Ljava.lang.String;" });

for(String f: ((String)flags).split("\\s+"))

    if(f.contains("GC")) System.out.println(f);

for(GarbageCollectorMXBean gc: ManagementFactory.getGarbageCollectorMXBeans())

    System.out.printf("%-20s%s%n", gc.getName(), Arrays.toString(gc.getMemoryPoolNames()));

我明白了


> jdk1.8.0_162\bin\java ...

-XX:+UseParallelGC

PS Scavenge         [PS Eden Space, PS Survivor Space]

PS MarkSweep        [PS Eden Space, PS Survivor Space, PS Old Gen]

在我的机器上,所以在没有选项的情况下运行确实在这个环境中选择了 ParallelGC。但请注意报告的名称“PS Scavenge”和“PS MarkSweep”,它们突出了选项和名称的另一个问题:典型配置考虑有两种垃圾收集算法,一种用于次要 gc,一种用于主要 gc。


当我尝试时-XX:-UseParallelGC,我得到


> jdk1.8.0_162\bin\java -XX:-UseParallelGC ...

-XX:+UseParallelGC

PS Scavenge         [PS Eden Space, PS Survivor Space]

PS MarkSweep        [PS Eden Space, PS Survivor Space, PS Old Gen]

这演示了 JVM 选项的问题,如下所示boolean:我无法关闭它们,因为 JVM 需要一个实际的其他垃圾收集器来选择。

所以要关闭并行,你可以使用-XX:+UseSerialGC:


> jdk1.8.0_162\bin\java -XX:+UseSerialGC ...

-XX:+UseSerialGC

Copy                [Eden Space, Survivor Space]

MarkSweepCompact    [Eden Space, Survivor Space, Tenured Gen]

为了比较


> jdk1.8.0_162\bin\java -XX:+UseConcMarkSweepGC ...

-XX:+UseConcMarkSweepGC

-XX:+UseParNewGC

ParNew              [Par Eden Space, Par Survivor Space]

ConcurrentMarkSweep [Par Eden Space, Par Survivor Space, CMS Old Gen]

请注意这两种算法中的每一种如何与一个选项相关联,但指定一个选项可以选择两种垃圾收集算法。


> jdk-9.0.4\bin\java ...

-XX:ConcGCThreads=2

-XX:+UseG1GC

G1 Young Generation [G1 Eden Space, G1 Survivor Space]

G1 Old Generation   [G1 Eden Space, G1 Survivor Space, G1 Old Gen]


> jdk-11.0.1\bin\java ...

-XX:ConcGCThreads=2

-XX:GCDrainStackTargetSize=64

-XX:+UseG1GC

G1 Young Generation [G1 Eden Space, G1 Survivor Space, G1 Old Gen]

G1 Old Generation   [G1 Eden Space, G1 Survivor Space, G1 Old Gen]


> jdk-11.0.1\bin\java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC ...

-XX:+UseEpsilonGC

Epsilon Heap        [Epsilon Heap]

因此,如果尝试获取相关Use…GC boolean选项的代码(即上面代码的第一部分,使用非标准com.sun.management:type=DiagnosticCommandMBean)找不到任何选项,您可以尝试使用 报告的垃圾收集器名称getGarbageCollectorMXBeans(),但正如您所见,这些名称与 JVM 选项的名称不匹配,因此您必须知道这些名称是如何关联的。


但归根结底,这些名称都不是真正的描述性名称,所以它们只有在您已经知道这些名称背后的内容时才有用……


查看完整回答
反对 回复 2022-07-06
  • 2 回答
  • 0 关注
  • 280 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号