在 $JAVA_HOME/bin 的目录下, 存在着许多小工具, 除了编译和运行 Java 程序外, 打包, 部署, 签名, 调试, 监控, 运维等各种场景都可能会用到它们。
列出正在运行的虚拟机进程, 并显示虚拟机执行主类 (Main Class, 也就是 main 方法所在的类) 的名称以及这些进程的本地虚拟机唯一 ID (LVMID,Local Virtual Machine Identifier)。
命令格式
jps [options] [<hostid>]
options 列表
选项 | 作用 |
---|---|
-q | 只输出 LVMID, 省略主类的名称 |
-m | 输出虚拟机进程启动时, 传递给 main 方法的参数 |
-l | 输出主类的全名称, 如果进程执行的是 jar 包, 输出 jar 包路径 |
-v | 输出 JVM 进程启动时的 JVM 参数 |
-V | 输出 LVMID 和主类的类名, 不带任何参数的 jps, 默认就是这个格式 |
jps 还可以查询开启了 RMI 服务的远程虚拟机进程状态, 参数 hostId 为 RMI 注册表中注册的主机名。开启 RMI 的步骤, 可以看这里。
用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类加载, 内存, 垃圾收集, 即时编译等运行时数据。
命令格式
jstat -<options> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
options 列表
选项 | 作用 |
---|---|
-class | 监视类加载/卸载数量, 总空间和类装载消耗时间 |
-gc | 监视堆状况, 包括 Eden 区/ 2 个 Survivor 区/老年代/永久代 等容量, 已用空间, 垃圾收集时间合计等信息 |
-gccapacity | 监视内容和 -gc 差不多, 但输出内容主要关注的是 Java 堆各个区域的使用到的最大, 最小空间 |
-gcutil | 监视内容和 -gc 差不多, 但输出内容主要关注的是 Java 堆各个区域已使用空间占总空间的百分比 |
-gccause | 和 -gcutil 功能一样, 但是会多输出导致上一次垃圾回收产生的原因 |
-gcnew | 监视新生代垃圾回收情况 |
-gcnewcapacity | 监视内容和 -gcnew 基本一样, 输出主要关注使用到的最大, 最小空间 |
-gcold | 监视老年代垃圾回收情况 |
-gcoldcapacity | 监视内容和 -gcold 基本一样, 输出主要关注使用到的最大, 最小空间 |
-gcpermcapacity | 输出永久代使用到的最大, 最小空间 |
-compiler | 输出即时编译器编译过的方法, 耗时等信息 |
-printcompilation | 输出已经被即时编译的方法 |
-t: 用于在最前面输出一个时间戳
-h: 格式 -h数字, 需要搭配后面的循环打印使用, 比如 5, 每个标题头下面输出 5 次结果后, 再次输出标题头, 再 5 次结果
vmid: 如果是本地的话, 就是 LVMID, 如果是远程的服务器的话, 则是类似于这样的格式 [protocol:][//]lvmid[@hostname[:port]/servername]
interval: 间隔多少毫秒查询 1 次, 如果为 数字 + s, 则是多少秒查询 1 次
count: 循环查询的次数
例子:
jstat -gcutil 2764
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 29.95 22.24 0.01 94.34 82.22 1 0.011 0 0.000 0.011
查询结果表明: 这台服务器的新生代 Eden 区 (E, 表示Eden) 使用了 22.24% 的空间, 2 个 Survivor 区 (S0, S1表示 Survivor0 和 Survivor1) 里面都是空的, 分别为空的和占了 29.95% 的空间, 老年代 (O, 表示 Old) 和 元空间 (M, 表示 Metaspace) 则分别使用了 0.01% 和 94.34% 的空间。
程序运行以来共发生 Minor GC (YGC, 表示 Young GC) 1次, 总耗时0.011秒; 发生 Full GC (FGC, 表示 Full GC) 0 次, 总耗时 (FGCT,表示 Full GC Time) 为 0.472 秒; 所有 GC 总耗时 (GCT, 表示 GC Time) 为 0.577 秒
实时查看和调整虚拟机各项参数
命令格式
jinfo -<options> <pid>
options 列表
选项 | 作用 |
---|---|
-flag name | 输出指定的 JVM 参数的值 |
-flag +/- name | 动态的启用/关闭指定的 JVM 参数 |
-flag name=value | 动态的设置 JVM 参数为给定的值 |
-flags | 输出所有的 JVM 参数 |
-sysprops | 输出当前的 Java 系统属性, 内容等同与 Java 内部的 System.getProperties() |
jmap 的作用并不仅仅是为了获取堆转储快照 (一般称为 heapdump 或 dump 文件), 它还可以查询 finalize 执行队列, Java 堆和方法区的详细信息, 如空间使用率, 当前用的是哪种收集器等
命令格式
jmap -<options> <pid>
options 列表
选项 | 作用 |
---|---|
-dump | 生成 Java 堆转储快照, 格式为 -dump:[live,]format=b,file=<文件名>, live 参数用于控制是否只 dump 出存活的对象 |
-finalizerinfo | 显示在 F-Queue 中等待 Finalizer 线程执行 finalize 方法的对象, 只在 Linux/Solaris 平台有效 |
-heap | 显示 Java 堆的详细信息, 如使用的是哪种收集器, 参数配置, 分代状况等, 只在 Linux/Solaris 平台有效 |
-histo | 显示堆中对象统计信息, 包含类/实例数量, 合集容量, 格式为 -histo[:live,][file=<文件名>], live 参数用于控制统计活对象, 同样的也可以直接把内容输出为文件 |
-permstat | 以 ClassLoader 为统计口径显示永久代内存状态, 只在 Linux/Solaris 平台有效 |
-F | 当虚拟机对 -dump 选项没有任何反应, 可使用这个参数强制 dump 出快照, 只在 Linux/Solaris 平台有效 |
除了手动生成快照的方式, 也可以通过配置 JVM 参数 XX: +HeapDumpOnOutOfMemoryError, 当程序内存溢出时, 生成 dump 文件
也可以通过设置 -XX: +HeapDumpOnCtrlBreak 参数, 然后通过 [Ctrl]+[Break] 键让虚拟机生成堆转储快照文件
在 Linux 中也可以通过 “Kill -3” 来获取堆转储快照
jhat 内置了一个微型的HTTP/Web服务器, 可以用来分析 jmap 生成的 dump 文件, 同时生成堆转储快照的分析结果后。
但是实际中很少会使用这个来分析 dump 文件, 有很多更智能的图形化工具可以使用。
命令格式
jhat dump文件
通过上面的命令, 当显示 “Server is Ready” 的提示后, 通过输入 localhost:7000 就能查看分析信息。
用于生成虚拟机当前时刻的线程快照 (一般称为 threaddump 或者 javacore 文件)。
线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合, 生成线程快照的 目的通常是定位线程出现长时间停顿的原因, 如线程间死锁, 死循环, 请求外部资源导致的长时间挂起等, 都是导致线程长时间停顿的常见原因。
线程出现停顿时通过 jstack 来查看各个线程的调用堆栈, 就可以获知没有响应的线程到底在后台做些什么事情, 或者等待着什么资源。
命令格式
jstack -<options> vmid
options 列表
选项 | 作用 |
---|---|
-F | 当正常的输出请求无响应时, 强制输出线程堆栈信息 |
-l | 除堆栈信息外, 显示锁的附加信息 |
-m | 如果调用到了本地方法的话, 输出 C/C++ 的堆栈 |
在 $JAVA_HOME/bin 下除了列出的这几个常用的工具外, 还有许多有用的工具, 如 javap 字节码分析工具, javac java 类文件转字节码文件等。
JHSDB 是一款基于服务性代理 (Serviceability Agent, SA) 实现的进程外调试工具。
服务性代理是 HotSpot 虚拟机中一组用于映射Java虚拟机运行信息的, 主要基于 Java 语言 (含少量 JNI 代码) 实现的 API 集合。
服务性代理以 HotSpot 内部的数据结构为参照物进行设计, 把这些 C++ 的数据抽象出 Java 模型对象, 相当于 HotSpot 的 C++ 代码的一个镜像。
通过服务性代理的 API, 可以在一个独立的 Java 虚拟机的进程里分析其他 HotSpot 虚拟机的内部数据, 或者从 HotSpot 虚拟机进程内存中 dump 出来的转储快照里还原出它的运行状态细节。
基于 JHSDB 的特点一般用于分析处于静止不变的程序, 比如卡在 debug 或者 dump 文件。
使用 JHSDB 的步骤
- 当前你有一个卡在 debug 的程序或者一份 dump 文件
- 启动 JHSDB, JDK8 中通过 java -cp $JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB, 启动 JHSDB 的图形化界面, 通过
java -cp $JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.CLHSDB 启动 JHSDB 的命令行界面, JDK9 及以后可以转到 $JAVA_HOME/bin,
执行 jhsdb hsdb (本人在 Mac 一直失败, 貌似 JDK8 在 Mac 上有 bug, 可以尝试升级 JDK 的版本, 在 Window10 成功关联上了)- 获取当前执行的中的 Java 程序的进程 ID
- 打开图形化界面, 左上角的 File, 选择关联进程 ID / dump 文件 / 服务地址
后面就是分析相关的操作了
操作可以看这里
JConsole (Java Monitoring and Management Console) 是一款基于 JMX (Java Management Extensions) 的可视化监视,管理工具。它的主要
功能是通过 JMX 的 MBean (Managed Bean) 对系统进行信息收集和参数动态调整。
在 $JAVA_HOME/bin 下面有一个 jconsole 的脚本, 直接执行它, 就会出现一个图形化界面, 在首页选中自己的进程, 就能进入分析。
VisualVM (All-in-One Java Troubleshooting Tool) 是功能最强大的运行监视和故障处理程序之一, 着它除了常规的运行监视, 故障处理外,还将提
供其他方面的能力, 譬如性能分析 (Profiling)。
在 $JAVA_HOME/bin 下面有一个 jvisualvm 的脚本, 直接执行它, 就会出现一个图形化界面, 在左侧的应用程序选中自己的程序即可。
VisualVM 可以做到:
- 显示虚拟机进程以及进程的配置, 环境信息 (jps, jinfo)
- 监视应用程序的处理器, 垃圾收集, 堆, 方法区以及线程的信息 (jstat, jstack)
- dump 以及分析堆转储快照 (jmap, jhat)
- 方法级的程序运行性能分析, 找出被调用最多, 运行时间最长的方法
- 离线程序快照: 收集程序的运行时配置, 线程 dump, 内存 dump 等信息建立一个快照, 可以将快照发送开发者处进行 Bug 反馈
- VisualVM 只提供了基础的功能, 同时支持大量的插件, 通过安装插件, 可以带来的无限可能性
Oracle 公司还开辟过带商业技术支持的工具
- 用于企业 JRE 定制管理的 AMC (Java Advanced Management Console) 控制台
- 系统跟踪的 JUT (Java Usage Tracker)
- 用于持续收集数据的飞行记录仪 JFR (Java Flight Recorder)
- 用于监控 Java 虚拟机的JMC (Java Mission Control)
通过 jmap 生成的 dump 文件, 除了可以通过 jhat 来分析外, 还可以通过其他的工具来分析, 如下面的这些工具
- MAT
- JProfiler
- 第三方的网站, 如 HeapDump
通过配置 JVM 启动参数生成的 GC 文件分析工具
- GCViewer
- 第三方的网站, 如 Ycrash GCeasy