JVM 性能监控工具

此博客为炼数成金JVM教程第七课

目录

  • 系统性能监控
    • 确定系统运行的整体状态,基本定位问题所在
  • Java自带的工具
    • 查看Java程序运行细节,进一步定位问题
  • 实战分析
    • 案例问题

Linux 性能监控

uptime
uptime的结果

系统时间
运行时间:例子中为7分钟
连接数: 每一个终端算一个进程
1,5,15分钟内的系统平均负载:运行队列中的平均进程数

top
JVM 性能监控工具_第1张图片

第一行输出与uptime相同
接着输出CPU和内存的统计结果
最后输出单个进程的CPU占用情况
这个命令可以知道那个程序占CPU最多
这里有一点需要注意,如果SWAP有大量的被使用,说明系统的实际内存比较欠缺,用到了交换空间,这会引起大量的IO读写,对系统造成比较大的影响。

vmstat
vmstat 1 4 每一秒采集一次,共采集四次

JVM 性能监控工具_第2张图片

可以统计系统的CPU,内存,swap,io等情况
CPU占用率(us)很高,上下文切换(cs)频繁,说明系统有线程正在频繁切换

pidstat

细致观察进程
监控CPU
监控IO
监控内存

JVM 性能监控工具_第3张图片

-p 执行进程id,-u 查看CPU, 1 3 每秒采样一次,一共采用三次

-t 显示线程的使用情况
JVM 性能监控工具_第4张图片

Tid 为线程ID, %cpu 为CPU使用率,CPU为在哪个核

检查IO,我们以磁盘IO为例
JVM 性能监控工具_第5张图片

可见,有一个进程的IO特别多,所以我们要去检查这个线程的情况。

Windows 性能监控

任务管理器

JVM 性能监控工具_第6张图片

Perfmon
windows 自带多功能性能监控工具

JVM 性能监控工具_第7张图片

Process Explorer
JVM 性能监控工具_第8张图片

pslist

windows 命令行参数
可用于自动化收集数据

显示java程序的运行情况
JVM 性能监控工具_第9张图片
JVM 性能监控工具_第10张图片

Java自带的工具

JVM 性能监控工具_第11张图片

jps

列出java进程,类似于ps命令
参数 -q 可以指定jsp只输出进程ID,不输出类的短名称
参数 -m可以输出传递给java进程(主函数)的参数
参数 -l 可以用于输出主函数的完整路径
参数 -v 可以显示传递给JVM的参数

JVM 性能监控工具_第12张图片

JVM 性能监控工具_第13张图片

JVM 性能监控工具_第14张图片

JVM 性能监控工具_第15张图片

jinfo

可以用来查看正在运行的Java应用程序的参数扩展,甚至支持在运行时,修改部分参数
-flag : 打印指定JVM的参数值
-flag [+|-] : 设置指定JVM参数的布尔值
-flag = : 设置指定JVM参数的值

JVM 性能监控工具_第16张图片

jmap

生成Java应用程序的堆快照和对象的统计信息
jmap -histo 2972 > c:\s.txt

JVM 性能监控工具_第17张图片

[I 表示整数数组
这个系统中最占用系统空间的是整数,有4983个实例,一共占用了6M的空间

Dump
jmap -dump:format=b,file=c:\heap.hprof 2972
format=b 表示二进制格式
把2972java进程的堆dump到c盘的hprof文件下

jstack

打印线程dump
-l 打印锁信息
-m 打印java和native的帧信息
-F 强制dump,当jstack 没有响应时使用

jstack 120 >> c:\a.txt

"main" #1 prio=6 os_prio=0 tid=0x0831c400 nid=0xecc runnable [0x0018f000]
   java.lang.Thread.State: RUNNABLE
    at org.eclipse.swt.internal.win32.OS.WaitMessage(Native Method)
    at org.eclipse.swt.widgets.Display.sleep(Display.java:4657)
    at org.eclipse.ui.application.WorkbenchAdvisor.eventLoopIdle(WorkbenchAdvisor.java:364)
    at org.eclipse.ui.internal.ide.application.IDEWorkbenchAdvisor.eventLoopIdle(IDEWorkbenchAdvisor.java:917)
    at org.eclipse.ui.internal.Workbench$3.eventLoopIdle(Workbench.java:487)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$9.run(PartRenderingEngine.java:1117)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:997)
    at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:140)
    at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:611)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:567)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:150)
    at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:354)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:181)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:636)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:591)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1450)

线程的名字是: main
tid: 线程id(jvm内部线程的唯一标识(通过java.lang.Thread.getId()获取,通常用自增方式实现。))
nid: 操作系统中的id(跟top命令查看的线程pid对应)

JConsole

图形化监控工具
可以查看Java应用程序的运行概况,监控堆信息,永久区使用情况,类加载情况等

JVM 性能监控工具_第18张图片
JVM 性能监控工具_第19张图片
JVM 性能监控工具_第20张图片
JVM 性能监控工具_第21张图片
建议: 我们在写程序时,最好给每一个线程加上一个好一点的名字,方便今后排查问题

Visual VM

Visual VM是一个功能强大的多合一故障诊断和性能监控的可视化工具

JVM 性能监控工具_第22张图片
JVM 性能监控工具_第23张图片
JVM 性能监控工具_第24张图片

性能监控:找到占用CPU时间最长的方法
JVM 性能监控工具_第25张图片

分析堆Dump
JVM 性能监控工具_第26张图片

实战分析
运行一程序ThreadBlockMain,期望输出Hello,World ,结果在程序运行后,程序卡死,没有预期输出。
JVM 性能监控工具_第27张图片
JVM 性能监控工具_第28张图片
从第二张图片可以看出来,main函数一直在跑,但是一直在等待一个socket的输入,导致了程序卡死

Java程序HoldCPUMain运行后,发现占用CPU很高,希望能找到原因。
JVM 性能监控工具_第29张图片
JVM 性能监控工具_第30张图片
我们希望知道3455的线程运行情况,为什么CPU占用高
这里写图片描述
JVM 性能监控工具_第31张图片
打印出来之后,发现线程3467的CPU占用在99%
把3467转成16进制为d8b, 去线程的dump里面查找 d8b 的线程,看看是为什么导致的
这里写图片描述
JVM 性能监控工具_第32张图片
可以看到,d8b对于的线程在跑,所以我们可以去看看HoldCPUMain的第八行在干什么,来确认问题。

死锁
JVM 性能监控工具_第33张图片

A要往南边走,但被B堵住,B想往东边走,但被C堵住,C想往北边走,但被D堵住,D想往西边走,但被A堵着,这个循环一旦形成,除非一辆车消失,否则一直堵着。这就是死锁。
我们可以用jstack找出死锁在哪里:
JVM 性能监控工具_第34张图片
可见 north 和 south 相互死锁。

如果是简单的死锁,jstack会直接给出结果
JVM 性能监控工具_第35张图片
JVM 性能监控工具_第36张图片
但如果是复杂的死锁,就需要自己看jstack的输出去判断。

你可能感兴趣的:(深入JVM内核—原理,诊断与优化)