JFR详细介绍与生产问题定位落地 - 3. 各种Event详细说明与JVM调优策略(2)

简介: JFR详细介绍与生产问题定位落地 - 3. 各种Event详细说明与JVM调优策略(2)

2. JAVA 应用相关


2.4. Java Monitor 同步锁相关

主要是三种 Event:

当进入同步块,尝试获取锁的时候,产生 JavaMonitorEnter Event;当调用 Object.wait() 进入等待时,会产生 JavaMonitorWait Event;当 锁升级(另一种说法是锁膨胀)时,产生 JavaMonitorWait Event。

下面我从网上看到的这张图,有助于理解这三种事件:


微信图片_20220624122007.jpg


  • JavaMonitorEnter(Java Monitor Blocked):进入 Java Monitor Event。当需要进入同步代码时(字节码 monitorenter),会产生这个 Event。在 default.jfc 中默认为启用的,并且会追踪堆栈,阈值是 20ms;采集的信息包括:开始时间,持续时间,结束时间,线程,Monitor Address,Monitor Class,之前持有这个 Monitor 的线程。
  • JavaMonitorInflated(Java Monitor Inflated):发生锁升级的时候的 Event。在 default.jfc 中默认为启用的,并且会追踪堆栈,阈值是 20ms;采集的信息包括:开始时间,持续时间,结束时间,线程,Monitor Address,Monitor Class,锁升级原因
  • JavaMonitorWait(Java Monitor Wait):调用 Object.wait() 进入等待时,会产生 JavaMonitorWait Event;在 default.jfc 中默认为启用的,并且会追踪堆栈,阈值是 20ms;采集的信息包括:开始时间,持续时间,结束时间,线程,Monitor Address,Monitor Class,唤醒线程Thread, 是否超时, 超时时间。

一般的在默认情况下, JavaMonitorEnter 和 JavaMonitorWait 采集到的在阈值以上的会比较多,一般不会有 JavaMonitorInflated 事件,除非发生 CPU 资源耗尽或者程序不断 dump 导致一直处于 safepoint。

但是并不是所有的 JavaMonitorEnter 和 JavaMonitorWait Event 都是我们关心的,如何快速找到我们关心的关键 Event 呢?

先举一个 JavaMonitorEnter 的例子: 从事件浏览器视角去看, Event 太多了,我们建一个 JavaMonitorEnter Event 的视图:


微信图片_20220624122022.jpg


一般的,我会按照 Monitor class 去分类看,争用同一个对象锁一般是同一个业务:


微信图片_20220624122034.jpg


微信图片_20220624122036.jpg



我们来看第一个计数最多的,点击这个分类,在下面的列表按照持续需时间倒序,查看线程以及堆栈:


微信图片_20220624122055.jpg


发现是因为本地缓存更新,导致比较慢,这里本地缓存是读取的数据库,读取的数据比较多,400ms 的比较正常。

我们再来看另一个,Monitor class 为 java.lang.Object 的:


微信图片_20220624122110.jpg


从堆栈上看出是获取 Lettuce 连接时候,锁等待了320ms。查看源代码,发现是连接初始化,导致比较慢,初始化好连接之后没再出现了。

这里建议,针对微服务应用,再调高阈值到 50ms。


2.5. Java Thread 相关

四个事件:

  • ThreadStart:线程开始, Thread.start() 时,就会产生这个 Event 记录
  • ThreadEnd:线程结束,就会产生这个 Event 记录
  • ThreadPark:一般在 await/notify 的 await 的时候,调用 Unsafe.park() 就会产生这个 Event 记录
  • ThreadSleep:线程休眠, Thread.sleep()时,就会产生这个 Event 记录

这些事件我们一般都不关心,Java 线程阻塞与热点方法和 CPU 消耗等,有其他的 Event,在 default.jfc 中这四个 Event 默认都是采集的,这里建议关闭这四个 Event 的采集


2.6. 网络IO socket 相关

  • SocketRead: 网络读,在 default.jfc 中,默认启用,并且会追踪堆栈,阈值是 20ms;采集的信息包括:开始时间,持续时间,结束时间,线程,远程 IP,读取字节大小,是否是流读取的末尾,远程 Host,远程 Port,超时时间
  • SocketWrite: 网络写,在 default.jfc 中,默认启用,并且会追踪堆栈,阈值是 20ms;采集的信息包括:开始时间,持续时间,结束时间,线程,远程 IP,写入字节大小,远程 Host,远程 Port

堆栈采集对于这种 Event 很重要,但是对于 Spring Cloud 这样的框架,调用层次极为复杂,可能默认采集堆栈深度(64)不够,需要增大才能看到自己的业务代码堆栈。但是要注意的一点是:堆栈采集深度,对于性能影响很大,以最坏的情况考虑,可以理解为增加多少倍的堆栈深度,对性能的影响就提高多少倍。 建议对于常态化的线上监控,堆栈深度最多不超过 128.


2.7. 一些统计数据相关

  • ClassLoaderStatistics: 类加载器相关统计数据,default.jfc 中默认打开,每个 DataChunk 采集一次,一般不会去关心类加载器的统计数据,建议关闭。
  • ClassLoadingStatistics: 类加载相关统计数据,default.jfc 中默认打开,每秒采集一次,一般不会去关心类加载的统计数据,建议关闭。
  • ExceptionStatistics:异常统计数据,default.jfc 中默认打开,每秒采集一次,一般异常通过日志处理,也不太会关心这个统计数据,建议关闭
  • JavaThreadStatistics:Java 线程数量统计数据,default.jfc 中默认打开,每秒采集一次线程数量,这个还有些参考意义,建议保留默认配置。采集的数据包括:到目前为止累计线程数量(包括已经 stop 的),当前活动线程数量,守护线程数量,采集时间内峰值线程数量。个人感觉不用每秒采集一次,改成每分钟即可。
  • ThreadAllocationStatistics:线程分配内存大小统计,包括了线程从开始到现在一共分配的内存大小(包括已释放的),default.jfc 中默认打开,每个 DataChunk 采集一次,参考意义不大,建议关闭


3. 虚拟机相关 Event


3.1. JVM 启动参数 Flag 相关

JVM 启动参数包含很多配置, 同时也可以通过 JVMTI,jcmd 命令等等动态修改这些配置, 如果我们想看这些配置以及修改的时间点,那么可以打开这些 Event 的采集:

  • BooleanFlag 与 BooleanFlagChange :布尔状态位以及变化。对应的就是通过类似于通过+``-配置的哪些状态位,例如-XX:+UseCompressedOops就是打开压缩对象指针
  • DoubleFlag 与 DoubleFlagChange:double状态位,例如-XX:InitialRAMPercentage=52.0配置初始内存堆栈占用比例(只有在没指定-Xmx-Xms的时候有效)
  • IntFlag 与 IntFlagChange
  • UnsignedIntFlag 与 UnsignedIntFlagChange
  • LongFlag 与 LongFlagChange
  • UnsignedLongFlag 与 UnsignedLongFlagChange
  • StringFlag 与 StringFlagChanged

这个对性能影响是很小的,所以在系统自带的 default.jfc 中就打开了。我这里建议还是打开,毕竟基本所有状态位是可以通过 jcmd 命令修改的,如果有对比需求,对比修改前还有修改后性能影响,那么状态位变换时间就很重要了


3.2. 类加载相关

主要包括三种 Event:

  • Class Define: 类定义
  • Class Load: 类加载
  • Class Unload: 类卸载

这些事件我们平常开发一般不会去关心,一般之后开发框架或者定位框架问题的时候,才会去关心类加载器相关的问题。而且这个用阿里开源的工具 Arthas更加好用(https://alibaba.github.io/arthas/sc.html):

$ sc -d demo.MathGame
class-info        demo.MathGame
code-source       /private/tmp/arthas-demo.jar
name              demo.MathGame
isInterface       false
isAnnotation      false
isEnum            false
isAnonymousClass  false
isArray           false
isLocalClass      false
isMemberClass     false
isPrimitive       false
isSynthetic       false
simple-name       MathGame
modifier          public
annotation
interfaces
super-class       +-java.lang.Object
class-loader      +-sun.misc.Launcher$AppClassLoader@3d4eac69
                    +-sun.misc.Launcher$ExtClassLoader@66350f69
classLoaderHash   3d4eac69
Affect(row-cnt:1) cost in 875 ms.
相关文章
|
1月前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
44 0
|
1月前
|
监控 架构师 Java
Java虚拟机调优的艺术:从入门到精通####
本文作为一篇深入浅出的技术指南,旨在为Java开发者揭示JVM调优的神秘面纱,通过剖析其背后的原理、分享实战经验与最佳实践,引领读者踏上从调优新手到高手的进阶之路。不同于传统的摘要概述,本文将以一场虚拟的对话形式,模拟一位经验丰富的架构师向初学者传授JVM调优的心法,激发学习兴趣,同时概括性地介绍文章将探讨的核心议题——性能监控、垃圾回收优化、内存管理及常见问题解决策略。 ####
|
2月前
|
监控 算法 Java
jvm-48-java 变更导致压测应用性能下降,如何分析定位原因?
【11月更文挑战第17天】当JVM相关变更导致压测应用性能下降时,可通过检查变更内容(如JVM参数、Java版本、代码变更)、收集性能监控数据(使用JVM监控工具、应用性能监控工具、系统资源监控)、分析垃圾回收情况(GC日志分析、内存泄漏检查)、分析线程和锁(线程状态分析、锁竞争分析)及分析代码执行路径(使用代码性能分析工具、代码审查)等步骤来定位和解决问题。
|
1月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
2月前
|
监控 算法 Java
Java虚拟机垃圾回收机制深度剖析与优化策略####
【10月更文挑战第21天】 本文旨在深入探讨Java虚拟机(JVM)中的垃圾回收机制,揭示其工作原理、常见算法及参数调优技巧。通过案例分析,展示如何根据应用特性调整GC策略,以提升Java应用的性能和稳定性,为开发者提供实战中的优化指南。 ####
47 5
|
2月前
|
监控 Java 编译器
Java虚拟机调优指南####
本文深入探讨了Java虚拟机(JVM)调优的精髓,从内存管理、垃圾回收到性能监控等多个维度出发,为开发者提供了一系列实用的调优策略。通过优化配置与参数调整,旨在帮助读者提升Java应用的运行效率和稳定性,确保其在高并发、大数据量场景下依然能够保持高效运作。 ####
39 1
|
2月前
|
存储 算法 Java
JVM进阶调优系列(10)敢向stop the world喊卡的G1垃圾回收器 | 有必要讲透
本文详细介绍了G1垃圾回收器的背景、核心原理及其回收过程。G1,即Garbage First,旨在通过将堆内存划分为多个Region来实现低延时的垃圾回收,每个Region可以根据其垃圾回收的价值被优先回收。文章还探讨了G1的Young GC、Mixed GC以及Full GC的具体流程,并列出了G1回收器的核心参数配置,帮助读者更好地理解和优化G1的使用。
|
2月前
|
监控 Java 测试技术
Elasticsearch集群JVM调优垃圾回收器的选择
Elasticsearch集群JVM调优垃圾回收器的选择
67 1
|
2月前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
2月前
|
监控 Java 编译器
Java虚拟机调优实战指南####
本文深入探讨了Java虚拟机(JVM)的调优策略,旨在帮助开发者和系统管理员通过具体、实用的技巧提升Java应用的性能与稳定性。不同于传统摘要的概括性描述,本文摘要将直接列出五大核心调优要点,为读者提供快速预览: 1. **初始堆内存设置**:合理配置-Xms和-Xmx参数,避免频繁的内存分配与回收。 2. **垃圾收集器选择**:根据应用特性选择合适的GC策略,如G1 GC、ZGC等。 3. **线程优化**:调整线程栈大小及并发线程数,平衡资源利用率与响应速度。 4. **JIT编译器优化**:利用-XX:CompileThreshold等参数优化即时编译性能。 5. **监控与诊断工