如何确定我使用哪个GC? [英] How to determine which GC I use?

查看:461
本文介绍了如何确定我使用哪个GC?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我没有指定任何GC,而且我认为我的JVM默认没有启用任何GC.

I didn't specify any GC, and I think my JVM have not any GC be enabled by default.

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

Of course I know that OpenJDK8 use ParallelGC by default, but I think it should can print by command line, like this:

java -XX:+PrintFlagsFinal|grep Use|grep GC

我希望输出包含 bool UseParallelOldGC = true {product},但不是:

I expect that the output contains bool UseParallelOldGC = true {product} but it is no :

     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:+PrintCommandLineFlags -version

我希望输出包含:XX:+UseParallelGC,但它也不是:

I expect that the output contains: XX:+UseParallelGC but it is no too:

-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(我认为是),对此情况我感到非常困惑.

the above output show that no any GC be enabled(I think so), I am very confuse by this situation.

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)

(from app starting until first major GC)

日志显示JVM堆分为newtenured,但没有打印GC类型.

The log show that JVM heap is divided into new and tenured, but without print GC type.

遗憾的是,我的环境中也无法使用jmap -heap {pid}来获取GC类型,因为jmap中没有此选项(-heap).

Sadly, I also cannot use jmap -heap {pid} to get the GC type because jmap without this option(-heap) in my env.

所以我想知道:

  1. 我真正使用的是哪个GC?
  2. 命令行选项(-XX:+PrintCommandLineFlags-XX:+PrintFlagsFinal)输出的信息正确吗?
  1. Which GC is what I use really?
  2. Is the command line options(-XX:+PrintCommandLineFlags and -XX:+PrintFlagsFinal) output information correct?

我的环境: k8s + docker,Alpine OpenJKD8

My env: k8s+docker, Alpine OpenJKD8

推荐答案

问题是实际上需要名称时,您正在查看类型为bool的JVM选项.这不是您的错,JVM的设计者决定给不同的垃圾收集器命名,但是提供类似于布尔选项的控件.

The problem is that you are looking at JVM options of type bool when you actually want a name. This is not your fault, the designers of the JVM decided to give the different garbage collectors names, but provide controls that look like boolean options.

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

So even if all these options are false, there is a garbage collector, but these options are not sufficient to get its name. But on the other hand, most of the names are insufficient for describing what these garbage collectors do, or how they differ from the other algorithms, anyway.

默认情况下,JDK8使用ParallelGC并不完全正确;如此答案所述,该算法是通过某种启发式方法选择的,尽管在大多数情况下,您最终还是会使用ParallelGC.

It’s not entirely correct that JDK8 uses ParallelGC by default; as this answer describes, the algorithm is selected by some heuristic, though, you’ll end up at ParallelGC in most cases.

使用以下代码

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.

on my machine, so running without options did select ParallelGC in this environment. But note the reported names "PS Scavenge" and "PS MarkSweep", which highlight another problem with the options and names: the typical configuration considers having two garbage collection algorithms, one for the minor gc and one for the major 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:

which demonstrates the problem of the JVM options looking like boolean: I can’t turn them off, as the JVM needs an actual other garbage collector to select.
So to turn off parallel, you could use -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]

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

Note how each of the two algorithms can be associated with an option, but specifying one option can select two garbage collection algorithms.

> 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=DiagnosticCommand MBean)找不到任何内容,则可以尝试使用getGarbageCollectorMXBeans()报告的垃圾收集器名称,但是如您所见,这些名称与JVM选项的名称不匹配,因此您必须知道这些名称的关联方式.

So in case the code trying to get the associated Use…GC boolean option (i.e. the first part of the code above, using the nonstandard com.sun.management:type=DiagnosticCommand MBean) doesn’t find any, you can try to use the garbage collector names as reported by getGarbageCollectorMXBeans(), but as you can see, these names do not match the names of the JVM options, so you have to know, how these names are associated.

但是最后,这些名称都没有真正的描述性,因此,只有当您已经知道这些名称背后的含义时,它们才有帮助.

But in the end, none of these names is really descriptive, so they all are only helpful if you already know what’s behind these names…

这篇关于如何确定我使用哪个GC?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆