乐趣区

关于java:troubleshoot之使用JFR分析性能问题

简介

java 程序的性能问题剖析是一个很艰难的问题。尤其是对于一个非常复杂的程序来说,剖析起来更是头疼。

还好 JVM 引入了 JFR,能够通过 JFR 来监控和剖析 JVM 的各种事件。通过这些事件的剖析,咱们能够找出潜在的问题。

明天咱们就来介绍一下对 java 性能剖析比拟重要的一些 JFR 事件。

GC 性能事件

一般来说,GC 会对 java 程序的性能操作产生比拟重要的影响。咱们能够应用 jfr 监控 jdk.GCPhasePause 事件。

上面是一个 jdk.GCPhasePause 的例子:

jfr print --events jdk.GCPhasePause flight_recording_1401comflydeanTestMemoryLeak89268.jfr

输入后果:

jdk.GCPhasePause {
  startTime = 19:51:49.798
  duration = 41.1 ms
  gcId = 2
  name = "GC Pause"
}

通过 GCPhasePause 事件,咱们能够统计总的 GC pause 工夫和均匀每一次 GC pause 的工夫。

一般来说 GC 是在后盾执行的,所以 GC 自身的执行工夫咱们并不需要关注,因为这并不会影响到程序的性能。咱们须要关注的是应用程序因为 GC 暂停的工夫。

思考上面两种状况,第一种独自的 GC 导致 GC pause 工夫过长。第二种是总的 GC pause 工夫过长。

如果是第一种状况,那么可能须要思考换一个 GC 类型,因为不同的 GC 类型在 pause 工夫和吞吐量的均衡间接会有不同的解决。同时咱们须要缩小 finalizers 的应用。

如果是第二种状况,咱们能够从上面几个方面来解决。

  • 减少 heap 空间大小。heap 空间越大,GC 的间隔时间就越长。总的 GC pause 工夫就会越短。
  • 尽量减少 tmp 对象的调配。咱们晓得为了晋升多线程的性能,JVM 会应用 TLAB 技术。一般来说小对象会调配在 TLAB 中,但如果是大对象,则会间接调配在 heap 空间中。然而大部分对象都是在 TLAB 中调配的。所以咱们能够同时关注 TLAB 和 TLAB 之外的两个事件:jdk.ObjectAllocationInNewTLAB 和 dk.ObjectAllocationOutsideTLAB。
  • 缩小调配频率。咱们能够通过 jdk.ThreadAllocationStatistics 来剖析。

同步性能

在多线程环境中,因为多线程会竞争共享资源,所以对资源的同步,或者锁的应用都会影响程序的性能。

咱们能够监控 jdk.JavaMonitorWait 事件。

jfr print --events jdk.JavaMonitorWait flight_recording_1401comflydeanTestMemoryLeak89268.jfr

咱们看一个后果:

jdk.JavaMonitorWait {
  startTime = 19:51:25.395
  duration = 2 m 0 s
  monitorClass = java.util.TaskQueue (classLoader = bootstrap)
  notifier = N/A
  timeout = 2 m 0 s
  timedOut = true
  address = 0x7FFBB7007F08
  eventThread = "JFR Recording Scheduler" (javaThreadId = 17)
  stackTrace = [java.lang.Object.wait(long)
    java.util.TimerThread.mainLoop() line: 553
    java.util.TimerThread.run() line: 506]
}

通过剖析 JavaMonitorWait 事件,咱们能够找到竞争最强烈的锁,从而进行更深层次的剖析。

IO 性能

如果应用程序有很多 IO 操作,那么 IO 操作也是会影响性能的要害一环。

咱们能够监控两种 IO 类型:socket IO 和 File IO。

绝对应的事件有:dk.SocketWrite,jdk.SocketRead,jdk.FileWrite,jdk.FileRead。

代码执行的性能

代码是通过 CPU 来运行的,如果 CPU 应用过高,也可能会影响到程序的性能。

咱们能够通过监听 jdk.CPULoad 事件来对 CPULoad 进行剖析。

jfr print --events jdk.CPULoad flight_recording_1401comflydeanTestMemoryLeak89268.jfr

看下运行后果:

jdk.CPULoad {
  startTime = 19:53:25.519
  jvmUser = 0.63%
  jvmSystem = 0.37%
  machineTotal = 20.54%
}

如果 jvm 应用的 cpu 比拟少,然而整个 machine 的 CPU 使用率比拟高,这阐明了有其余的程序在占用 CPU。

如果 JVM 本人的 CPU 应用就很高的话,那么就须要找到这个占用 CPU 的线程进行进一步剖析。

其余有用的 event

除了下面提到的 event 之外,还有一些其余有用的咱们能够关注的 event。

比方线程相干的:jdk.ThreadStart,jdk.ThreadEnd,jdk.ThreadSleep,jdk.ThreadPark。

如果你应用 JMC,那么能够很直观的查看 JFR 的各种事件。

所以举荐大家应用 JMC。

本文作者:flydean 程序那些事

本文链接:http://www.flydean.com/jvm-diagnostic-perform-issue/

本文起源:flydean 的博客

欢送关注我的公众号: 程序那些事,更多精彩等着您!

退出移动版