当前位置: 首页 > 知识库问答 >
问题:

如何确定我使用哪个GC?

蒋栋
2023-03-14

我没有指定任何GC,我认为我的JVM默认情况下没有启用任何GC。

当然,我知道 OpenJDK8 默认使用并行GC,但我认为它应该可以通过命令行打印,如下所示:

< code > Java-XX:print flags final | grep Use | grep GC

我期望输出包含< code > 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}
     bool UseGCOverheadLimit                        = true                                {product}
     bool UseGCTaskAffinity                         = false                               {product}
     bool UseMaximumCompactionOnSystemGC            = true                                {product}
     bool UseParNewGC                               = false                               {product}
     bool UseParallelGC                             = false                               {product}
     bool UseParallelOldGC                          = false                               {product}
     bool UseSerialGC                               = false                               {product}

java-XX:PrintCommand dLineFlags-version

我期望输出包含:< code>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(我认为是这样),我对这种情况感到非常困惑。

GC日志输出如下:

OpenJDK 64-Bit Server VM (25.181-b13) for linux-amd64 JRE (1.8.0_181-b13), built on Oct 23 2018 11:39:12 by "buildozer" with gcc 6.4.0
Memory: 4k page, physical 28780816k(6283132k free), swap 0k(0k free)
CommandLine flags: -XX:InitialHeapSize=460493056 -XX:MaxHeapSize=7367888896 -XX:+PrintGC -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+PrintGCDeta
ils -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+UseCompressedClassPointers -XX:+UseCompressedOops 
{Heap before GC invocations=0 (full 0):
 def new generation   total 135168K, used 120192K [0x0000000608c00000, 0x0000000611ea0000, 0x000000069b2a0000)
  eden space 120192K, 100% used [0x0000000608c00000, 0x0000000610160000, 0x0000000610160000)
  from space 14976K,   0% used [0x0000000610160000, 0x0000000610160000, 0x0000000611000000)
  to   space 14976K,   0% used [0x0000000611000000, 0x0000000611000000, 0x0000000611ea0000)
 tenured generation   total 300416K, used 0K [0x000000069b2a0000, 0x00000006ad800000, 0x00000007c0000000)
   the space 300416K,   0% used [0x000000069b2a0000, 0x000000069b2a0000, 0x000000069b2a0200, 0x00000006ad800000)
 Metaspace       used 20532K, capacity 20780K, committed 20992K, reserved 1067008K
  class space    used 2628K, capacity 2726K, committed 2816K, reserved 1048576K
2019-02-25T06:29:46.105+0000: 2.890: [GC (Allocation Failure) 2019-02-25T06:29:46.105+0000: 2.890: [DefNew
Desired survivor size 7667712 bytes, new threshold 1 (max 15)
- age   1:   15335424 bytes,   15335424 total
: 120192K->14976K(135168K), 0.0238110 secs] 120192K->18041K(435584K), 0.0238765 secs] [Times: user=0.01 sys=0.01, real=0.02 secs] 
Heap after GC invocations=1 (full 0):
 def new generation   total 135168K, used 14976K [0x0000000608c00000, 0x0000000611ea0000, 0x000000069b2a0000)
  eden space 120192K,   0% used [0x0000000608c00000, 0x0000000608c00000, 0x0000000610160000)
  from space 14976K, 100% used [0x0000000611000000, 0x0000000611ea0000, 0x0000000611ea0000)
  to   space 14976K,   0% used [0x0000000610160000, 0x0000000610160000, 0x0000000611000000)
 tenured generation   total 300416K, used 3065K [0x000000069b2a0000, 0x00000006ad800000, 0x00000007c0000000)
   the space 300416K,   1% used [0x000000069b2a0000, 0x000000069b59e660, 0x000000069b59e800, 0x00000006ad800000)
 Metaspace       used 20532K, capacity 20780K, committed 20992K, reserved 1067008K
  class space    used 2628K, capacity 2726K, committed 2816K, reserved 1048576K
}
2019-02-25T06:29:46.129+0000: 2.914: Total time for which application threads were stopped: 0.0241189 seconds, Stopping threads took: 0.0000181 seconds
{Heap before GC invocations=1 (full 0):
 def new generation   total 135168K, used 21860K [0x0000000608c00000, 0x0000000611ea0000, 0x000000069b2a0000)
  eden space 120192K,   5% used [0x0000000608c00000, 0x00000006092b93f8, 0x0000000610160000)
  from space 14976K, 100% used [0x0000000611000000, 0x0000000611ea0000, 0x0000000611ea0000)
  to   space 14976K,   0% used [0x0000000610160000, 0x0000000610160000, 0x0000000611000000)
 tenured generation   total 300416K, used 3065K [0x000000069b2a0000, 0x00000006ad800000, 0x00000007c0000000)
   the space 300416K,   1% used [0x000000069b2a0000, 0x000000069b59e660, 0x000000069b59e800, 0x00000006ad800000)
 Metaspace       used 20982K, capacity 21132K, committed 21248K, reserved 1067008K
  class space    used 2667K, capacity 2758K, committed 2816K, reserved 1048576K
2019-02-25T06:29:46.187+0000: 2.972: [Full GC (Metadata GC Threshold) 2019-02-25T06:29:46.187+0000: 2.972: [Tenured: 3065K->9617K(300416K), 0.0270556 secs] 24926K-
>9617K(435584K), [Metaspace: 20982K->20982K(1067008K)], 0.0271334 secs] [Times: user=0.03 sys=0.00, real=0.03 secs] 
Heap after GC invocations=2 (full 1):
 def new generation   total 135296K, used 0K [0x0000000608c00000, 0x0000000611ec0000, 0x000000069b2a0000)
  eden space 120320K,   0% used [0x0000000608c00000, 0x0000000608c00000, 0x0000000610180000)
  from space 14976K,   0% used [0x0000000610180000, 0x0000000610180000, 0x0000000611020000)
  to   space 14976K,   0% used [0x0000000611020000, 0x0000000611020000, 0x0000000611ec0000)
 tenured generation   total 300416K, used 9617K [0x000000069b2a0000, 0x00000006ad800000, 0x00000007c0000000)
   the space 300416K,   3% used [0x000000069b2a0000, 0x000000069bc04698, 0x000000069bc04800, 0x00000006ad800000)
 Metaspace       used 20982K, capacity 21132K, committed 21248K, reserved 1067008K
  class space    used 2667K, capacity 2758K, committed 2816K, reserved 1048576K
}

(从应用程序启动到第一个主要GC)

日志显示 JVM 堆分为堆和永久堆,但没有打印 GC 类型。

遗憾的是,我也不能使用< code>jmap -heap {pid}来获取GC类型,因为jmap在我的env中没有这个选项(-heap)。

所以我想知道:

  1. 我真正用的是哪个GC?
  2. 命令行选项(-XX: PrintCommand dLineFlags-XX: PrintFlagsFinal)输出信息是否正确?

我的环境:k8s docker,Alpine OpenJKD8

共有2个答案

高朝明
2023-03-14

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

因此,即使所有这些选项都是的,也有一个垃圾回收器,但这些选项不足以获取其名称。但另一方面,大多数名称都不足以描述这些垃圾回收器的作用,或者它们与其他算法的区别。

JDK8 默认使用并行GC并不完全正确。正如这个答案所描述的,该算法是由一些启发式算法选择的,但是,在大多数情况下,您最终会进入 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-scave”和“PS-MarkSweep”,这突出了选项和名称的另一个问题:典型配置考虑使用两个垃圾收集算法,一个用于次要gc,另一个用于主要gc。

当我尝试< code>-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选项看起来像< code>boolean的问题:我不能关闭它们,因为JVM需要一个真正的其他垃圾收集器来选择。< br >所以要关闭并行,您可以使用< code>-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 Generathtml" target="_blank">ion [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]

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

但是最后,这些名字都不是真正描述性的,所以只有当你已经知道这些名字背后的含义时,它们才是有用的…

张高澹
2023-03-14

<代码>jcmd

例如。

$ /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

更新

如果没有打印< code>-XX:Use*GC标志,则意味着使用了串行GC。这只发生在JDK 8和更早的版本上。从JDK 9开始,JVM会自动设置一个< code>Use*GC标志。详情请见JDK-8068582。

 类似资料:
  • 问题内容: 无论是从Ipython会话内部还是从脚本内部进行交互,您如何确定matplotlib正在使用哪个后端? 问题答案: 使用该函数获取一个字符串,该字符串表示正在使用哪个后端:

  • 我有一个客户端,它通过指定TLS 1.2发送握手请求到维基,但维基用TLS 1.0版回复。我如何让维基使用1.2版

  • 如果我记得Jasmine中有一个命令可以记录我运行到控制台的Jasmine的确切版本,但我不记得它是什么了。我肯定我以前在某个地方见过这个,现在我真的需要它,我在任何地方都找不到它。有人知道它是什么吗? 编辑:使用< code>jasmine.getEnv()发布的解决方案。versionString()不工作——对于阅读本文的任何mods来说,修复该问题是作为一个新问题开始还是在此继续更好?

  • 问题内容: 是否有任何工具可以列出应用程序有效使用哪些类以及何时有效使用某些类,甚至更好地自动修剪JAR库以仅提供被引用和使用的类? 问题答案: 请记住,正如停机问题所证明的那样,您不能肯定地说某个特定类已使用或未使用。至少在任何中等复杂的应用程序上。这是因为类不仅在编译时绑定,而且可以加载: 基于XML配置(例如Spring); 从属性文件加载(例如JDBC驱动程序名称); 动态添加注释; 由于

  • 假设我有一个卷,我知道它的名称或id。 我想确定使用卷的容器列表(它们的名称或id)。 我可以使用什么命令来检索这些信息? 我认为它可以存储在docker volume inspect的输出中