Fork me on GitHub

JVM(3)

JVM 学习资源

JVM 系列文章

以下图片参考上方链接

JVM 性能监测工具剖析

注:代码中以//开头的为笔者备注\

名称 主要作用
jps 显示指定系统内所有的 HotSpot 虚拟机进程
jstat 用于收集 HotSpot 虚拟机各方面的运行数据
jinfo 显示虚拟机配置信息
jmap 生成虚拟机的内存转储快照(即 heapdump 文件)
jhat 用于分析 heapdump 文件,会建立一个 HTTP 服务器,用户可使用浏览器查看
jstack 显示虚拟机的线程快照

推荐阅读:JDK 内置工具使用

jps

  • 查看虚拟机进程,JVM Process Status
  • 格式:jps[option][hostid]
  • option:
    • -q:只输出 LVMID
    • -m:输出虚拟机进程启动时传递给主类 main()函数的参数
    • -l:输出主类的全名,如果进程执行的是 jar 包,输出 jar 路径
    • -v:输出虚拟机进程启动时 JVM 参数
  • hostid:指定特定主机,若不填默认本机
1
2
3
4
5
6
7
[root@VM_0_2_centos ~]# jps -l
18340 sun.tools.jps.Jps //当前查询进程,即 jps 进程
27848 /opt/gitblit/gitblit.jar
14479 gitblit.jar

//说明当前有 1447927848 两个虚拟机进程

jstat

  • 收集 HotSpot 虚拟机各方面的运行数据,JVM Statistics Monitoring
  • 格式:jstat[option vmid [interval[s|ms][count] ] ]
  • vmid:
  • option:
    • -class,监视装载、卸载数量、总空间、装载耗时
    • -gc,监视 Java 堆状况,包括 Eden 区、两个 Survivor 区、老年代、永久代的容量,已用空间、GC 时间合计等信息
    • -gcutil,监视内容类似gc,但主要关注已使用空间占总空间的百分比
    • 。。。不详述
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@VM_0_2_centos ~]# jstat -class 14479 // 查看类
Loaded Bytes Unloaded Bytes Time // 装数量 空间 卸数量 空间 装耗时
12042 21286.9 4260 6564.5 8.09

[root@VM_0_2_centos ~]# jstat -gcnew 14479 // 监视新生代的 GC
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
2688.0 2688.0 0.0 143.0 15 15 1344.0 22016.0 17339.3 1595 5.526
//S0C、S0U 分别是第一个 Survivor 区的总容量和使用量;
TT、MTT 是持有次数限制与最大持有次数限制;
DSS 是当前需要 Survivor 的容量
EC、EU 分别是新生代中总容量和已使用量;
YGC 是app启动到当前新生代 GC 的次数;
YGCT 是app启动到当前新生代 GC 的总耗时(s);

[root@VM_0_2_centos ~]# jstat -gcutil 14479 // 关注已使用空间的百分比
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 5.32 78.76 84.37 95.41 91.95 1595 5.526 26 2.402 7.928
//S0、S1、E、O、M分别是两个 Survivor、新生代、老年代、永久代的使用百分比;
CCS 是压缩使用比例
YGC、FGC 是app启动到当前新生代、老年代 GC 的次数;
YGCT、FGCT 是app启动到当前新生代、老年代 GC 的总耗时(s);
GCT 是app启动到当前 GC 的总耗时(s);

S0C:年轻代中第一个survivor(幸存区)的容量 (字节) 
S1C:年轻代中第二个survivor(幸存区)的容量 (字节) 
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节) 
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节) 
EC:年轻代中Eden(伊甸园)的容量 (字节) 
EU:年轻代中Eden(伊甸园)目前已使用空间 (字节) 
OC:Old代的容量 (字节) 
OU:Old代目前已使用空间 (字节) 
PC:Perm(持久代)的容量 (字节) 
PU:Perm(持久代)目前已使用空间 (字节) 
YGC:从应用程序启动到采样时年轻代中gc次数 
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s) 
FGC:从应用程序启动到采样时old代(全gc)gc次数 
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s) 
GCT:从应用程序启动到采样时gc用的总时间(s) 
NGCMN:年轻代(young)中初始化(最小)的大小 (字节) 
NGCMX:年轻代(young)的最大容量 (字节) 
NGC:年轻代(young)中当前的容量 (字节) 
OGCMN:old代中初始化(最小)的大小 (字节) 
OGCMX:old代的最大容量 (字节) 
OGC:old代当前新生成的容量 (字节) 
PGCMN:perm代中初始化(最小)的大小 (字节) 
PGCMX:perm代的最大容量 (字节)   
PGC:perm代当前新生成的容量 (字节) 
S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比 
S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比 
E:年轻代中Eden(伊甸园)已使用的占当前容量百分比 
O:old代已使用的占当前容量百分比 
P:perm代已使用的占当前容量百分比 
S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节) 
S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节) 
ECMX:年轻代中Eden(伊甸园)的最大容量 (字节) 
DSS:当前需要survivor(幸存区)的容量 (字节)(Eden区已满) 
TT: 持有次数限制 
MTT : 最大持有次数限制

jinfo

  • 实时查看 JVM 各项参数,功能不全,一般只用flag
  • 格式:jinfo[option] pid
  • option:
    • -flag:

jmap

  • 生成堆转储快照
  • 格式:jmap[option]vmid
  • option:
    • -dump:生成快照
    • -heap:显示 Java 堆详细信息
    • -histo:显示堆中对象统计信息,包括类、实例数量、合计容量

jhat

  • 虚拟机堆转储快照分析工具,JVM Heap Analysis Tool
  • 功能较少,推荐使用更专业的工具,如 VisualVM 等

jstack

  • Java 堆栈跟踪工具,用来用来监控 JVM 中每一条线程正在执行的方法堆栈的集合,想知道某个线程正在做什么,或者因为什么不响应了
  • 格式:jstack[option]vmid
  • option:
    • -l:除堆栈外,显示关于锁的附加信息
    • -F:当正常输出的请求不被响应时,强制输出线程堆栈
    • -m:如果调用到本地方法的话,可以显示 C/C++ 的堆栈
[root@VM_0_2_centos ~]# jstack -l 14479  //查的gitblit.jar
2018-10-01 10:31:58
Full thread dump OpenJDK 64-Bit Server VM (25.171-b10 mixed mode):

//jstack 连接
"Attach Listener" #168 daemon prio=9 os_prio=0 tid=0x00007f9c18075d70 nid=0x1d6a waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE //说明正常运行

   Locked ownable synchronizers:
    - None

"qtp1279149968-166" #166 prio=5 os_prio=0 tid=0x00007f9c1088fd10 nid=0x22af waiting on condition [0x00007f9c07dfe000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000ece65c08> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
    at org.eclipse.jetty.util.BlockingArrayQueue.poll(BlockingArrayQueue.java:389)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.idleJobPoll(QueuedThreadPool.java:531)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.access$700(QueuedThreadPool.java:47)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:590)
    at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
    - None

...
//删减
...

"qtp1279149968-11-selector-ServerConnectorManager@2f0559e0/0" #11 prio=5 os_prio=0 tid=0x00007f9c40638230 nid=0x389c runnable [0x00007f9c0f735000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
    at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x00000000ed2fdb60> (a sun.nio.ch.Util$3)
    - locked <0x00000000ed2fdb70> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000000ed2fdb18> (a sun.nio.ch.EPollSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:101)
    at org.eclipse.jetty.io.SelectorManager$ManagedSelector.select(SelectorManager.java:600)
    at org.eclipse.jetty.io.SelectorManager$ManagedSelector.run(SelectorManager.java:549)
    at org.eclipse.jetty.util.thread.NonBlockingThread.run(NonBlockingThread.java:52)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
    at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
    - None

"Gitblit Shutdown Monitor" #8 daemon prio=5 os_prio=0 tid=0x00007f9c4062f4a0 nid=0x389a runnable [0x00007f9c0f937000]
   java.lang.Thread.State: RUNNABLE
    at java.net.PlainSocketImpl.socketAccept(Native Method)
    at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
    at java.net.ServerSocket.implAccept(ServerSocket.java:545)
    at java.net.ServerSocket.accept(ServerSocket.java:513)
    at com.gitblit.GitBlitServer$ShutdownMonitorThread.run(GitBlitServer.java:517)

   Locked ownable synchronizers:
    - None

"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007f9c400eaf20 nid=0x3897 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f9c400dc2f0 nid=0x3896 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f9c400da750 nid=0x3895 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f9c400d8c20 nid=0x3894 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f9c400af720 nid=0x3893 in Object.wait() [0x00007f9c44197000]
   java.lang.Thread.State: WAITING (on object monitor) //等待资源来唤醒
    at java.lang.Object.wait(Native Method)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x00000000ecdb7dd8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:212)

   Locked ownable synchronizers:
    - None

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f9c400ab4b0 nid=0x3892 in Object.wait() [0x00007f9c44298000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x00000000ecdb7f90> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

   Locked ownable synchronizers:
    - None

"main" #1 prio=5 os_prio=0 tid=0x00007f9c400093c0 nid=0x3890 in Object.wait() [0x00007f9c47b48000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000ece31020> (a java.lang.Object)
    at java.lang.Object.wait(Object.java:502)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.join(QueuedThreadPool.java:381)
    - locked <0x00000000ece31020> (a java.lang.Object)
    at org.eclipse.jetty.server.Server.join(Server.java:556)
    at com.gitblit.GitBlitServer.start(GitBlitServer.java:461)
    at com.gitblit.GitBlitServer.main(GitBlitServer.java:124)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.moxie.MxLauncher.main(MxLauncher.java:129)

   Locked ownable synchronizers:
    - None

"VM Thread" os_prio=0 tid=0x00007f9c400a2000 nid=0x3891 runnable

"VM Periodic Task Thread" os_prio=0 tid=0x00007f9c4001b250 nid=0x3898 waiting on condition

JNI global references: 281

// 着重关注 Deadlock 死锁、Waiting on condition 等待资源或条件来唤醒、Blocked 阻塞、Waiting on monitor entry 等待获取锁。
// 如果 CPU 高,线程可能有死循环,需要关注 Runable 状态 
-------------The End-------------