почему моя JVM выполнила 3 раза FullGC при запуске

#java #garbage-collection #jvm #metaspace

#java #сбор мусора #jvm #метапространство

Вопрос:

Моя работа — это задание Flink TaskManager. Когда он запускается, он запускается 3 раза GC. Я не знаю, почему, когда он достиг MetadataGCThreshold, он увеличил занимаемое пространство, в то время как метапространство не изменилось и даже увеличилось между GC.

Я думал, что FullGC уменьшит занимаемое пространство и некоторое пространство метапространства. 😯

 Java HotSpot(TM) 64-Bit Server VM (25.211-b12) for linux-amd64 JRE (1.8.0_211-b12), built on Apr  1 2019 20:39:34 by "java_re" with gcc 7.3.0
Memory: 4k page, physical 4194304k(3951532k free), swap 0k(0k free)
CommandLine flags: -XX: HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/flink-jvm -XX:InitialHeapSize=2899312640 -XX:MaxDirectMemorySize=9223370937343148032 -XX:MaxHeap
Size=2899312640 -XX:NewSize=2147483648 -XX: PrintFlagsFinal -XX: PrintGC -XX: PrintGCDetails -XX: PrintGCTimeStamps -XX: UseCompressedClassPointers -XX: UseCompressedOops 

# first GC, the Tenured space even increase?!
2.452: [Full GC (Metadata GC Threshold) 2.452: [Tenured: 0K->14532K(735232K), 0.0623627 secs] 167782K->14532K(2622720K), [Metaspace: 20876K->20876K(1067008K)], 0.0624443 secs] [Times: user=0.05 
sys=0.01, real=0.07 secs] 

11.656: [Full GC (System.gc()) 11.656: [Tenured: 14532K->27057K(735232K), 0.1974158 secs] 395065K->27057K(2622720K), [Metaspace: 32454K->32454K(1077248K)], 0.1975190 secs] [Times: user=0.18 sys=
0.02, real=0.20 secs] 

65.942: [Full GC (Metadata GC Threshold) 65.942: [Tenured: 27057K->55025K(735232K), 0.2259224 secs] 512544K->55025K(2622720K), [Metaspace: 53760K->53760K(1097728K)], 0.2262134 secs] [Times: user
=0.18 sys=0.03, real=0.23 secs] 
  

=================================================================
Продолжение
благодаря ответу Стивена я установил начальный размер метапространства на -XX:MetaspaceSize=134217728 . Я запускаю задание дважды, второй раз с этим параметром jvm. не было FullGC из-за Metadata GC Threshold .

 ######  之前: first time
bash-4.2$ tailf gc_log_2020-08-26_07-19-05_pid84.log 
Java HotSpot(TM) 64-Bit Server VM (25.241-b26) for linux-amd64 JRE (1.8.0_241-b26), built on Jan  6 2020 08:59:51 by "java_re" with gcc 7.3.0
Memory: 4k page, physical 4194304k(3920180k free), swap 0k(0k free)
CommandLine flags: -XX: HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/flink-jvm -XX:InitialHeapSize=2899312640 -XX:MaxDirectMemorySize=9223370937343148032 -XX:MaxHeapSize=2899312640 -XX:NewSize=2147483648 -XX: PrintFlagsFinal -XX: PrintGC -XX: PrintGCDetails -XX: PrintGCTimeStamps -XX: UseCompressedClassPointers -XX: UseCompressedOops 
2.359: [Full GC (Metadata GC Threshold) 2.359: [Tenured: 0K->14643K(735232K), 0.0526437 secs] 167782K->14643K(2622720K), [Metaspace: 20937K->20937K(1067008K)], 0.0527307 secs] [Times: user=0.04 sys=0.01, real=0.05 secs] 
14.576: [Full GC (System.gc()) 14.576: [Tenured: 14643K->27136K(735232K), 0.1894478 secs] 417611K->27136K(2622720K), [Metaspace: 32274K->32274K(1077248K)], 0.1895372 secs] [Times: user=0.15 sys=0.02, real=0.19 secs] 

######  添加了metadata参数之后(-XX:MetaspaceSize=134217728), second time with param
bash-4.2$ tailf gc_log_2020-08-26_07-23-19_pid85.log 
Java HotSpot(TM) 64-Bit Server VM (25.241-b26) for linux-amd64 JRE (1.8.0_241-b26), built on Jan  6 2020 08:59:51 by "java_re" with gcc 7.3.0
Memory: 4k page, physical 4194304k(3920136k free), swap 0k(0k free)
CommandLine flags: -XX: HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/flink-jvm -XX:InitialHeapSize=2899312640 -XX:MaxDirectMemorySize=9223370937343148032 -XX:MaxHeapSize=2899312640 -XX:MetaspaceSize=134217728 -XX:NewSize=2147483648 -XX: PrintFlagsFinal -XX: PrintGC -XX: PrintGCDetails -XX: PrintGCTimeStamps -XX: UseCompressedClassPointers -XX: UseCompressedOops 
5.196: [Full GC (System.gc()) 5.196: [Tenured: 0K->27063K(735232K), 0.2379232 secs] 973363K->27063K(2622720K), [Metaspace: 32544K->32544K(1077248K)], 0.2380344 secs] [Times: user=0.25 sys=0.03, real=0.24 secs] 
  

Ответ №1:

Почему моя JVM выполнила 3 раза FullGC при запуске?

Первый и третий полные GC были вызваны тем, что metaspace достиг своего текущего порога и нуждался в росте. Поскольку metaspace в основном используется для хранения вещей, связанных с кодом, это означает, что Flink загружает много кода или генерирует много динамических прокси или что-то в этом роде.

Вы могли бы рассмотреть возможность увеличения начального размера метапространства.

Второй полный GC был вызван явным System.gc() вызовом. Я предполагаю, что это делает Flink.

Я думал, что FullGC уменьшит занимаемое пространство.

Не обязательно. Если полный GC был вызван заполнением метапространства, то вы вполне могли обнаружить, что многие объекты в новом пространстве были сохранены. В первом случае ясно, что это произошло, поскольку до GC выделенное пространство было пустым.

… в то время как метапространство не изменяется и даже увеличивается между GCS

Это означает, что GC не находит никакого мусора в метапространстве. Я бы ожидал, что использование metaspace to уменьшится, только если ClassLoader экземпляр (и все его классы, и все их экземпляры) станут недоступными. Ожидается, что использование метапространства увеличится во время запуска. Это потенциально касается только в том случае, если оно продолжит увеличиваться после запуска приложения и полного прогрева JVM.