- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
转载:Flink jvm参数配置GC日志
生产环境上,或者其他要测试 GC 问题的环境上,一定会配置上打印GC日志的参数,便于分析 GC 相关的问题。
但是可能很多人配置的都不够“完美”,要么是打印的内容过少,要么是输出到控制台,要么是一个大文件被覆盖,要么是……
本文带你一步一步,配置一个完美的 GC 日志打印策略
为了保留足够多的“现场证据”,最好是把 GC 相关的信息打印的足够完整。而且你的程序真的不差你GC时打印日志I/O消耗的那点性能
打印 GC 日志的第一步,就是开启 GC 打印的参数了,也是最基本的参数。
-XX:+PrintGCDetails -XX:+PrintGCDateStamps
为了分析 GC 时的晋升情况和晋升导致的高暂停,不看对象年龄分布日志怎么行
-XX:+PrintTenuringDistribution
输出内容示例:
1. Desired survivor size 59244544 bytes, new threshold 15 (max 15)
1. - age 1: 963176 bytes, 963176 total
1. - age 2: 791264 bytes, 1754440 total
1. - age 3: 210960 bytes, 1965400 total
1. - age 4: 167672 bytes, 2133072 total
1. - age 5: 172496 bytes, 2305568 total
1. - age 6: 107960 bytes, 2413528 total
1. - age 7: 205440 bytes, 2618968 total
1. - age 8: 185144 bytes, 2804112 total
1. - age 9: 195240 bytes, 2999352 total
1. - age 10: 169080 bytes, 3168432 total
1. - age 11: 114664 bytes, 3283096 total
1. - age 12: 168880 bytes, 3451976 total
1. - age 13: 167272 bytes, 3619248 total
1. - age 14: 387808 bytes, 4007056 total
1. - age 15: 168992 bytes, 4176048 total
每次发生 GC 时,对比一下 GC 前后的堆内存情况,更直观
-XX:+PrintHeapAtGC
输出内容示例:
1. {Heap before GC invocations=
0 (full
0):
1. garbage-first heap total 1024000K, used 324609K [
0x0000000781800000,
0x0000000781901f40,
0x00000007c0000000)
1. region size 1024K,
6 young (6144K),
0 survivors (0K)
1. Metaspace used 3420K, capacity 4500K, committed 4864K, reserved 1056768K
1.
class space used 371K, capacity 388K, committed 512K, reserved 1048576K
1. Heap after GC invocations=
1 (full
1):
1. garbage-first heap total 1024000K, used 21755K [
0x0000000781800000,
0x0000000781901f40,
0x00000007c0000000)
1. region size 1024K,
0 young (0K),
0 survivors (0K)
1. Metaspace used 3420K, capacity 4500K, committed 4864K, reserved 1056768K
1.
class space used 371K, capacity 388K, committed 512K, reserved 1048576K
1. }
暂停时间是 GC 最重要的指标,肯定不能少
-XX:+PrintGCApplicationStoppedTime
输出内容示例:
Total time for which application threads were stopped: 0.0254260 seconds, Stopping threads took: 0.0000218 seconds
进入STW阶段之前,需要要找到一个合适的 safepoint ,这个指标一样很重要(非必选,出现 GC 问题时最好加上此参数调试)
-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1
输出内容示例:
1. vmop [threads: total initially_running wait_to_block] [
time: spin block sync cleanup vmop] page_trap_count
1. 0.371: ParallelGCFailedAllocation [
10
0
0 ] [
0
0
0
0
7 ]
0
1. Execute
full gc...dataList has been promoted
to cms
old space
1. vmop [threads: total initially_running wait_to_block] [
time: spin block sync cleanup vmop] page_trap_count
1. 0.379: ParallelGCSystemGC [
10
0
0 ] [
0
0
0
0
16 ]
0
1. vmop [threads: total initially_running wait_to_block] [
time: spin block sync cleanup vmop] page_trap_count
1. 0.396:
no vm operation [
9
1
1 ] [
0
0
0
0
341 ]
0
强引用/弱引用/软引用/虚引用/finalize 方法万一有问题,不得打印出来看看?
-XX:+PrintReferenceGC
输出内容示例:
1. 2021-
02-
19T12:
41:
30.462+
0800:
5072726.605: [SoftReference,
0 refs,
0.0000521 secs]
1. 2021-
02-
19T12:
41:
30.462+
0800:
5072726.605: [
WeakReference,
0 refs,
0.0000069 secs]
1. 2021-
02-
19T12:
41:
30.462+
0800:
5072726.605: [FinalReference,
0 refs,
0.0000056 secs]
1. 2021-
02-
19T12:
41:
30.462+
0800:
5072726.605: [PhantomReference,
0 refs,
0 refs,
0.0000059 secs]
1. 2021-
02-
19T12:
41:
30.462+
0800:
5072726.605: [JNI Weak Reference,
0.0000131 secs],
0.4635293 secs]
完整参数
1. # requireds
1. -XX:+PrintGCDetails
1. -XX:+PrintGCDateStamps
1. -XX:+PrintTenuringDistribution
1. -XX:+PrintHeapAtGC
1. -XX:+PrintReferenceGC
1. -XX:+PrintGCApplicationStoppedTime
1. # optional
1. -XX:+PrintSafepointStatistics
1. -XX:PrintSafepointStatisticsCount=1
上面只是定义了打印的内容,默认情况下,这些日志会输出到控制台(标准输出)。那如果你的程序日志也输出到控制台呢,这个日志内容就会很乱,分析起来很麻烦。如果你是追加的方式(比如 tomcat 的 catalina.out 就是追加),这个文件会越来越大,分析起来就要命了。
所以需要一种分割日志的机制,这个机制嘛……JVM自然是提供的。
JVM提供了几个用于分割 GC 日志的参数:
1. # GC日志输出的文件路径
1. -Xloggc:
/path/to/gc.log
1. # 开启日志文件分割
1. -XX:+UseGCLogFileRotation
1. # 最多分割几个文件,超过之后从头开始写
1. -XX:NumberOfGCLogFiles=
14
1. # 每个文件上限大小,超过就触发分割
1. -XX:GCLogFileSize=
100M
按照这个参数,每个GC日志只要超过20M就会进行分割,最多分割5个文件,文件名依次是gc.log.0,gc.log.1,gc.log.2,gc.log.3,gc.log.4, .....
看似很美好,几行配置就搞定了输出文件的问题。但是这种方式有一些问题:
这个覆盖的问题就有点恶心了,每次启动覆盖之前的历史日志……这谁能忍?
于是有另一种解决方案。不使用 JVM 提供的日志分割功能,而是每次启动用时间戳命名日志文件,这样可以每次启动都使用不同的文件,就不会出现覆盖的问题了。
1. # 使用-%t作为日志文件名
1. -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:
/path/to/gc-%t.log
1. # 生成的文件名是这种:gc-2021-03-29_20-41-47.log
可是这样就完美吗?
虽然没有覆盖的问题,但由于没有日志分割的功能,每次启动后只有一个GC日志文件,单个日志文件可能会非常巨大。过大的日志文件分析起来是很麻烦的,必须得分割。
这里只需要稍微调整一下策略,将 JVM 分割和时间戳命名两种方案结合,就可以得到最优的方式了。
1. # GC日志输出的文件路径
1. -Xloggc:
/path/to/gc-%t.log
1. # 开启日志文件分割
1. -XX:+UseGCLogFileRotation
1. # 最多分割几个文件,超过之后从头开始写
1. -XX:NumberOfGCLogFiles=
14
1. # 每个文件上限大小,超过就触发分割
1. -XX:GCLogFileSize=
100M
配置时间戳作文 GC 日志文件名的同时,也配置JVM的GC日志分割策略。这样一来,既保证了 GC 文件不会被覆盖,又保证了单个 GC 文件的大小不会过大,完美!
最终得到的日志文件名会像这个样子:
1. # 必备
1. -XX:+PrintGCDetails
1. -XX:+PrintGCDateStamps
1. -XX:+PrintTenuringDistribution
1. -XX:+PrintHeapAtGC
1. -XX:+PrintReferenceGC
1. -XX:+PrintGCApplicationStoppedTime
1. # 可选
1. -XX:+PrintSafepointStatistics
1. -XX:PrintSafepointStatisticsCount=1
1. # GC日志输出的文件路径
1. -Xloggc:/path/to/gc-%t.log
1. # 开启日志文件分割
1. -XX:+UseGCLogFileRotation
1. # 最多分割几个文件,超过之后从头文件开始写
1. -XX:NumberOfGCLogFiles=14
1. # 每个文件上限大小,超过就触发分割
1. -XX:GCLogFileSize=100M
是否可以复制一个完整的 JVM,并且在故障转移的情况下只需将负载转移到复制的 JVM 上? 如果是,那我们该怎么做呢? 最佳答案 如果您的应用程序是 Web 应用程序,请阅读“集群”和“负载平衡”。大
我读了下面的话,但我想知道它们之间的区别...... JVM 规范、JVM 实现、JVM 运行时 最佳答案 JVM 规范:描述 JVM 应如何运行的文档。 JVM 实现:基于 JVM 规范的 JVM
我目前有四个不同的 java 应用程序,它们由 .bat 文件启动的 jar 运行,这些文件位于 Windows XP Embedded 开始菜单的 starup 文件夹中。我还启动了 Firefox
有人能给我一些关于强制 64 位 jvm 作为 32 位 jvm 运行的想法吗? 我需要为蓝牙连接编写一个 jse 桌面应用程序。为此,我需要实现 Bluecove jar 。它只有 32 位文件。所
我看到过关于这个问题的多条评论——有人说是,有人说不是,许多答案模棱两可。任何人都可以用更简单的术语描述它所在的位置吗?在一篇文章中,我什至看到有人说它与类加载器加载类的类内存共享相同的内存位置 -
我正在寻找所有可能的 jvm 退出代码的完整列表(不是 java System.exit(x))。我使用搜索引擎唯一能找到的是 SIGTERM 退出代码列表:http://journal.thobe.
为了监视任何正常的 Java 进程 JVM,我们可以使用 Attach API。是否有可用于监控 WebSphere JVM 的 API? 最佳答案 您可以使用 PMI(性能监控基础设施)来监控 JV
这个问题在这里已经有了答案: 8年前关闭。 Possible Duplicate: Java - C-Like Fork? 我想知道如何从 JDK fork 子 JVM,甚至有可能这样做吗? 一些框架
JVM 上的哪些图灵完备语言实现不使用 JVM 堆栈作为调用堆栈? (我问是因为我想在同一个线程中实现 Scala 和另一种语言之间的协程。) 最佳答案 闪蝶 SISC(方案代码的第二解释者) 曾经不
我看到here除了 Java 之外,还有很多语言可以在 JVM 上运行。我对在 JVM 中运行的其他语言的整个概念有些困惑。所以: 为 JVM 使用其他语言有什么优势? 为 JVM 编写语言/编译器需
我已经运行了 straced JVM (OpendJDK 11): strace -e trace=mmap java -Xms8192m Main 输出是: mmap(NULL, 8192, PRO
我已经运行了 straced JVM (OpendJDK 11): strace -e trace=mmap java -Xms8192m Main 输出是: mmap(NULL, 8192, PRO
我编写了一个简单的数独求解器。为了粗略测试性能,我使用简单的 System.currentTimeMillis 调用。 我在文本文件中准备了一组初始数独配置。该程序读取该文件并解决每个数独配置。运行测
JVM 被广泛使用:Scala、Groovy、Jython 等。我听说它被描述为“卓越”、“出色”和“严重低估”。为什么? 更具体地说,是什么让 JVM 独一无二?随着所有资金投入 .NET,或者 C
这个问题在这里已经有了答案: 10年前关闭。 Possible Duplicate: Are there any Java VMs which can save their state to a fi
想象一下 6-7 台服务器的设置都完全相同Java 版本“1.6.0_18”OpenJDK 运行时环境 (IcedTea6 1.8) (fedora-36.b18.fc11-i386)OpenJDK
(如有错误请指正) 我了解到,当您通过发出 java 命令来运行 java 程序时, java MyProg 程序将在新的 JVM 上运行。 什么将程序加载到新的 JVM 中?是生成新线程的 JRE
我们有一个使用 JNI 的桌面应用程序偶尔会导致 JVM 崩溃。幸运的是,JVM 会生成一个 hs_err_pidXXXX.log 文件,这对于调试此类错误非常有用。然而,它似乎总是转到当前工作目录,
我在命令提示符下运行一个程序集 jar 文件并得到下面的异常。并导致终止。 Uncaught error from thread [ccp-akka.persistence.dispatchers.d
一、什么是Java虚拟机 虚拟机:指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 ,是物理机的软件实现。常用的虚拟机有VMWare,Visual Box,Java
我是一名优秀的程序员,十分优秀!