深度探索JFR - JFR详细介绍与生产问题定位落地 - 1. JFR说明与启动配置(下)

简介: 深度探索JFR - JFR详细介绍与生产问题定位落地 - 1. JFR说明与启动配置(下)

通过 JVM 启动参数启用以及 JVM 参数说明


在 OpenJDK 11 版本之后,启动参数被简化了很多很多;目前JFR涉及的参数仅仅只有两个,一个负责启动(-XX:StartFlightRecording),一个负责配置(-XX:FlightRecorderOptions)。JDK 8中的-XX:+FlightRecorder打开 FlightRecorder 状态位在 OpenJDK 11 中不再需要了,目前仅需一个参数就能启动 JFR。 这里我们举一个例子:


java -XX:StartFlightRecording=disk=true,dumponexit=true,filename=recording.jfr,maxsize=1024m,maxage=1d,settings=profile,path-to-gc-roots=true test.Main

核心就是 -XX:StartFlightRecording,有了这个参数就会启用 JFR 记录。其中的涉及配置有:


配置key | 默认值 | 说明


---|---|---


delay | 0 | 延迟多久后启动 JFR 记录,支持带单位配置, 例如 delay=60s(秒), delay=20m(分钟), delay=1h(小时), delay=1d(天),不带单位就是秒, 0就是没有延迟直接开始记录。一般为了避免框架初始化等影响,我们会延迟 1 分钟开始记录(例如Spring cloud应用,可以看下日志中应用启动耗时,来决定下这个时间)。

disk | true | 是否写入磁盘,这个就是上文提到的, global buffer 满了之后,是直接丢弃还是写入磁盘文件。


dumponexit | false | 程序退出时,是否要dump出 .jfr文件

duration | 0 | JFR 记录持续时间,同样支持单位配置,不带单位就是秒,0代表不限制持续时间,一直记录。

filename | 启动目录/hotspot-pid-26732-id-1-2020_03_12_10_07_22.jfr,pid 后面就是 pid, id 后面是第几个 JFR 记录,可以启动多个 JFR 记录。最后就是时间。 | dump的输出文件


name | 无 | 记录名称,由于可以启动多个 JFR 记录,这个名称用于区分,否则只能看到一个记录 id,不好区分。

maxage | 0 | 这个参数只有在 disk 为 true 的情况下才有效。最大文件记录保存时间,就是 global buffer 满了需要刷入本地临时目录下保存,这些文件最多保留多久的。也可以通过单位配置,没有单位就是秒,默认是0,就是不限制


maxsize | 250MB | 这个参数只有在 disk 为 true 的情况下才有效。最大文件大小,支持单位配置, 不带单位是字节,m或者M代表MB,g或者G代表GB。设置为0代表不限制大小**。虽然官网说默认就是0,但是实际用的时候,不设置会有提示**: No limit specified, using maxsize=250MB as default. 注意,这个配置不能小于后面将会提到的 maxchunksize 这个参数。


path-to-gc-roots| false | 是否记录GC根节点到活动对象的路径,一般不打开这个,首先这个在我个人定位问题的时候,很难用到,只要你的编程习惯好。还有就是打开这个,性能损耗比较大,会导致FullGC一般是在怀疑有内存泄漏的时候热启动这种采集,并且通过产生对象堆栈无法定位的时候,动态打开即可。一般通过产生这个对象的堆栈就能定位,如果定位不到,怀疑有其他引用,例如 ThreadLocal 没有释放这样的,可以在 dump 的时候采集 gc roots


settings | 默认是 default.jfc,这个位于 `$JAVA_HOME/lib/jfr/default.jfc`| 采集 Event 的详细配置,采集的每个 Event 都有自己的详细配置。另一个 JDK 自带的配置是 profile.jfc,位于 `$JAVA_HOME/lib/jfr/profile.jfc`。这个配置文件里面的配置是怎么回事,我们后面会涉及。


至于前面章节中提到的那些 Buffer 的大小,是在另一个配置参数中配置,一般我们不改这些配置,用默认的就能满足我们的需求了,这里列出下:

-XX:FlightRecorderOptions 相关的参数

配置key | 默认值 | 说明

-------------------|---|-------------------------

allow_threadbuffers_to_disk | false | 是否允许 在 thread buffer 线程阻塞的时候,直接将 thread buffer 的内容写入文件。默认不启用,一般没必要开启这个参数,只要你设置的参数让 global buffer 大小合理不至于刷盘很慢,就行了。


globalbuffersize | 如果不设置,根据设置的 memorysize 自动计算得出 | 单个 global buffer 的大小,一般通过 memorysize 设置,不建议自己设置

maxchunksize | 12M | 存入磁盘的每个临时文件的大小。默认为12MB,不能小于1M。可以用单位配置,不带单位是字节,m或者M代表MB,g或者G代表GB。注意这个大小最好不要比 memorySize 小,更不能比 globalbuffersize 小,否则会导致性能下降

memorysize | 10M | JFR的 global buffer 占用的整体内存大小,一般通过设置这个参数,numglobalbuffers 还有 globalbuffersize 会被自动计算出。可以用单位配置,不带单位是字节,m或者M代表MB,g或者G代表GB。


numglobalbuffers | 如果不设置,根据设置的 memorysize 自动计算得出 | global buffer的个数,一般通过 memorysize 设置,不建议自己设置

old-object-queue-size | 256 | 对于Profiling中的 Old Object Sample 事件,记录多少个 Old Object,这个配置并不是越大越好。记录是怎么记录的,会在后面的各种 Event 介绍里面详细介绍。我的建议是,一般应用256就够,时间跨度大的,例如 maxage 保存了一周以上的,可以翻倍


repository | 等同于 -Djava.io.tmpdir 指定的目录 | JFR 保存到磁盘的临时记录的位置

retransform | true | 是否通过 JVMTI 转换 JFR 相关 Event 类,如果设置为 false,则只在 Event 类加载的时候添加相应的 Java Instrumentation,这个一般不用改,这点内存 metaspace 还是足够的


samplethreads | true | 这个是是否开启线程采集的状态位配置,只有这个配置为 true,并且在 Event 配置中开启线程相关的采集(这个后面会提到),才会采集这些事件。

stackdepth | 64 | 采集事件堆栈深度,有些 Event 会采集堆栈,这个堆栈采集的深度,统一由这个配置指定。注意这个值不能设置过大,如果你采集的 Event种类很多,堆栈深度大很影响性能。比如你用的是 default.jfc 配置的采集,堆栈深度64基本上就是不影响性能的极限了。你可以自定义采集某些事件,增加堆栈深度。


threadbuffersize | 8KB | threadBuffer 大小,最好不要修改这个,如果增大,那么随着你的线程数增多,内存占用会增大。过小的话,刷入 global buffer 的次数就会变多。8KB 就是经验中最合适的。


配置与 JFR 的架构联系:


微信图片_20220624121445.jpg


注意这些配置的联系与区别


1.disk=true 与 dumponexit=true, 这两个配置完全不是一回事。disk=true,仅仅代表如果 global buffer 满了,将这个写入文件并不是用户可以看到的,只会写入 repository 配置的目录,默认是临时目录,这个临时目录地址是-Djava.io.tmpdir指定的,默认为: - linux: /tmp 目录 - windows: C:\Users\你的用户\AppData\Temp

配置了 disk=true 之后,就会在临时目录产生一个文件夹,命名格式是:时间_pid,例如:2020_03_12_08_04_45_10916;里面的文件就是一个又一个的 Data trunk,表现为一个又一个的 .jfr 文件。最新的文件 会跟随一个 .part :


--/2020_03_12_08_04_45_10916
|----2020_03_12_08_04_45.jfr
|----2020_03_12_08_05_12.jfr
|----2020_03_12_08_05_55.jfr
|----2020_03_12_08_06_08.jfr
|----2020_03_12_08_06_08.part

每个 .jfr 文件的大小, 就是 Data Chunk 的大小,这个大小如何配置,会在后面的 jcmd 启动并配置 JFR 中提到。 dumponexit=true 代表在程序退出的时候,强制dump一次将数据存入 filename 配置的输出文件。只有用户手动 dump, 或者是 dumponexit 触发的 dump, 用户才能正常看到 .jfr 文件。输出这个文件其实很快, 就是将内存中所有 beffer 以及临时文件夹 中的 .jfr文件的内容,输出到用户指定的 .jfr 文件中。一般内存中的 buffer 很小,是MB级别的,这个是可以配置的,注意不要配置很大,否则可能会内存不足,最重要的是可能会使老年代增大导致FullGC。


2.JFR相关的内存占用到底有多大?主要是两部分,一部分是 global buffer,另一部分是 thread local buffer。 global buffer 总大小由上面提到的 memorysize 自动计算得出,总大小就是 memorysize。所以, JFR 相关的占用内存大小为: thread 数量 * thread buffer 大小 + memory size


通过 jcmd 命令启用


jcmd 命令相关的参数与 JVM 参数涉及的配置参数,其实是一样的,我们来看。

  1. jcmd <pid> JFR.start。启动 JFR 记录,参数和-XX:StartFlightRecording一模一样,请参考上面的表格。但是注意这里不再是逗号分割,而是空格 示例:
jcmd 21 JFR.start name=profile_online maxage=1d maxsize=1g

这个就代表启动一个名称为 profile_online, 最多保留一天,最大保留 1G 的本地文件记录

  1. jcmd <pid> JFR.stop. 停止 JFR 记录,需要传入名称,例如如果要停止上面打开的,则执行:
jcmd 21 JFR.stop name=profile_online


参数:

参数 | 默认值 | 描述 ---|----|--- name | 无 | 指定要停止的 JFR 记录名称 copy_to_file | 无 | 停止时同时复制到文件,指定文件输出位置

  1. jcmd <pid> JFR.check,查看当前正在执行的 JFR 记录。


示例:

jcmd 21 JFR.check


输出:

21:
Recording 1: name=profile_online maxsize=1.0GB maxage=1d (running)


参数:

参数 | 默认值 | 描述 ---|----|--- name | 无 | 指定要查看的 JFR 记录名称 verbose | false | 是否查看每种 Event 采集详细配置

  1. jcmd <pid> JFR.configure,如果不传入参数,则是查看当前配置,传入参数就是修改配置。配置与-XX:FlightRecorderOptions的一模一样。请参考上面的表格 示例:
./jcmd 21 JFR.configure

输出:

Repository path: /tmp/2020_03_18_08_41_44_21
Stack depth: 64
Global buffer count: 20
Global buffer size: 512.0 kB
Thread buffer size: 8.0 kB
Memory size: 10.0 MB
Max chunk size: 12.0 MB
Sample threads: true

示例:

./jcmd 21 JFR.configure stackdepth=65

输出:

21:
Stack depth: 65
  1. jcmd <pid> JFR.dump

参数:

参数 | 默认值 | 描述

---|----|---

name | 无 | 指定要查看的 JFR 记录名称

filename | 无 | 指定文件输出位置

maxage | 0 | dump最多的时间范围的文件,可以通过单位配置,没有单位就是秒,默认是0,就是不限制

maxsize | 0 | dump最大文件大小,支持单位配置, 不带单位是字节,m或者M代表MB,g或者G代表GB。设置为0代表不限制大小

begin | 无 | dump开始位置, 可以这么配置:09:00, 21:35:00, 2018-06-03T18:12:56.827Z, 2018-06-03T20:13:46.832, -10m, -3h, or -1d

end : | 无| dump结束位置,可以这么配置: 09:00, 21:35:00, 2018-06-03T18:12:56.827Z, 2018-06-03T20:13:46.832, -10m, -3h, or -1d (STRING, no default value)


path-to-gc-roots| false | 是否记录GC根节点到活动对象的路径,一般不记录,dump 的时候打开这个肯定会触发一次 fullGC,对线上应用有影响。最好参考之前对于 JFR 启动记录参数的这个参数的描述,考虑是否有必要

相关文章
|
3月前
|
监控 数据可视化 Java
jvm性能调优实战 - 31从测试到上线_如何分析JVM运行状况及合理优化
jvm性能调优实战 - 31从测试到上线_如何分析JVM运行状况及合理优化
53 1
|
Arthas Cloud Native Java
是谁在调用我?使用 arthas+jprofiler 做复杂链路分析
Arthas 是阿里巴巴开源的应用诊断利器,提供了 profiler 命令,可以生成热点火焰图。通过采样录制调用链路来做性能分析,极大提升了线上排查性能问题的效率。
是谁在调用我?使用 arthas+jprofiler 做复杂链路分析
|
存储 安全 Java
深度探索JFR - JFR定位线上问题实例 - JFR导致的雪崩问题定位与解决
深度探索JFR - JFR定位线上问题实例 - JFR导致的雪崩问题定位与解决
深度探索JFR - JFR定位线上问题实例 - JFR导致的雪崩问题定位与解决
|
XML 存储 监控
java日志(系统运行监控)
.什么是日志? 记录系统运行的过程和详情,并可以进行永久存储
201 0
java日志(系统运行监控)
|
缓存 监控 Oracle
JFR诊断增强学习笔记
快速学习JFR诊断增强
132 0
JFR诊断增强学习笔记
|
存储 缓存 监控
深度探索JFR - JFR详细介绍与生产问题定位落地 - 1. JFR说明与启动配置(上)
深度探索JFR - JFR详细介绍与生产问题定位落地 - 1. JFR说明与启动配置(上)
深度探索JFR - JFR详细介绍与生产问题定位落地 - 1. JFR说明与启动配置(上)
|
XML Java BI
JFR详细介绍与生产问题定位落地 - 2. 通过实例了解JMC 与 Event 结构与详细配置
JFR详细介绍与生产问题定位落地 - 2. 通过实例了解JMC 与 Event 结构与详细配置
JFR详细介绍与生产问题定位落地 - 2. 通过实例了解JMC 与 Event 结构与详细配置
|
Arthas 缓存 开发框架
JFR详细介绍与生产问题定位落地 - 3. 各种Event详细说明与JVM调优策略(2)
JFR详细介绍与生产问题定位落地 - 3. 各种Event详细说明与JVM调优策略(2)
JFR详细介绍与生产问题定位落地 - 3. 各种Event详细说明与JVM调优策略(2)
|
消息中间件 监控 算法
JFR详细介绍与生产问题定位落地 - 3. 各种Event详细说明与调优策略(1)
JFR详细介绍与生产问题定位落地 - 3. 各种Event详细说明与调优策略(1)
JFR详细介绍与生产问题定位落地 - 3. 各种Event详细说明与调优策略(1)
|
存储 设计模式 缓存
深度探索JFR - 3. 各种Event详细说明与JVM调优策略(3)
深度探索JFR - 3. 各种Event详细说明与JVM调优策略(3)
深度探索JFR - 3. 各种Event详细说明与JVM调优策略(3)