1.JDK 命令行工具
Java 开发人员肯定都知道 JDK 的 bin 目录有 "java.exe","javac.exe" 这两个命令行工具, 但并非所有程序员都了解过 JDK 的 bin 目录之中其他命令行程序的作用. 每次 JDK 更新, bin 目录下命令行工具的数量和功能总会不知不觉地增强.
主要包括用于监控虚拟机和故障处理的工具. 这些工具被 Sun 公司作为礼物附赠给 JDK 的使用者. 如下图:
可以看到这些工具的程序体积都异常小巧. 基本都稳定在 17K 左右. 这并非 JDK 开发团队刻意把他们制作得如此精炼, 而是这些命令行工具大多数是 JDK/lib/tools.jar 类库的一层薄包装而已, 它们主要的功能代码是在 tools 类库中实现的.
之所以这样做, 是因为当应用程序部署到生产环境后, 无论是直接接触物理服务器还是远程 Telnet 到服务器上都可能会受到限制. 借助 tools.jar 类库里面的接口, 我们可以直接在应用程序中实现功能强大的监控分析功能.
下面列举 JDK 主要命令行监控工具的用途.
1.jps: 虚拟机就进程状况工具
JDK 的很多小工具的名字都参考了 UNIX 命令的命名方式, jps 名字像 UNIX 的 ps 命令之外, 也和 ps 命令类似: 可以列出正在运行的虚拟机进程. 并显示虚拟机执行主类 (Main Class,main() 函数所在的类)名称以及这些进程的本地虚拟机唯一 ID(Local Virtual Machine Identifier,LVMID).
虽然功能比较单一, 但它是使用频率最高的 JDK 命令行工具, 因为其他的 JDK 工具大多需要输入它查询到的 LVMID 来确定要监控的是哪一个虚拟机进程. 对于本地虚拟机进程来说, LVMID 与操作系统的进程 ID 是一致的. 使用 Windows 的任务管理器或者 UNIX 的 ps 命令也可以
查询到虚拟机进程的 LVMID, 但如果同时启动多个虚拟机进程, 无法根据进程名称定位时, 那只有依赖 jps 命令显示主类的功能才能区分了.
jps 命令格式如下:
现在我们打开一个 eclispe, 写一段程序, 例子如下:
- package hjc.test9a;
- import java.util.Scanner;
- /**
- * Created by cong on 2018/4/5.
- */
- public class Main {
- public Main() {
- }
- public static void main(String[] args) {
- Scanner sc = new Scanner(System.in);
- sc.next();
- }
- }
连续运行 2 次, 打开 cmd, 再用 jps 查看, 如下:
2.jstat: 虚拟机统计信息监控工具
jstat(JVM Statistics Monitoring Tool)是用于监控虚拟机各种运行状态信息的命令行工具. 它可以显示本地或者远程虚拟机进程中的类装载, 内存, 垃圾收集, JIT 编译等运行数据, 在没有 GUI 图形界面, 只提供了纯文本控制台环境的服务器上,
它将是运行期定位虚拟机性能问题的首选工具.
jstat 命令格式为:
jstat [ option vmid [interval [s|ms] [count]] ]
对于命令格式中的 VMID 与 LVMID 需要特别说明一下: 如果是本地虚拟机进程, VMID 与 LVMID 是一致的, 如果是远程虚拟机进程, 那 VMID 的格式应当是:
参数 interval 和 count 代表查询间隔和次数, 如果省略这两个参数, 说明只查询一次. 假设要美 250 毫秒查询一次进程 2764 垃圾收集情况, 一个查询 20 次, 那命令应当是:
jstat -gc 2764 250 20
选项 option 代表着用户希望查询的虚拟机信息, 主要分为 3 类: 类装载, 垃圾收集, 运行期编译状况, 具体选项及作用请参考如下列表:
jstat 监控选项众多, 这里仅举一个例子演示如何查看监控结果. 继续运行上面的例子如下:
3.jinfo:Java 配置信息工具
jinfo(Configuration Info for Java) 的作用是实时地查看和调整虚拟机各项参数. 使用 jps 命令的 - v 参数可以查看虚拟机启动时显式指定的参数列表, 但如果想知道未被显式指定的参数的系统默认值, 除了去找资料, 就只能使用 jinfo 的 - flag 选项进行查询了(如果
只限于 JDK1.6 或以上版本的话, 使用 java -XX:+PrintFlagsFianl 查看参数默认值也是一个很好的选择),jinfo 还可以使用 - sysprops 选项把虚拟机进程的 System.getProperties()的内容打印出来. 这个命令在 JDK1.5 时期已经伴随 Linux 的 JDK 发布, 当时只提供了信息查询的功能,
JDK1.6 之后, jinfo 在 Windows 和 Linux 平台都有提供, 并且加入了运行期修改参数的能力, 可以使用 - flag [+|-] name 或者 -flag name=value 修改一部分运行期可写的虚拟机参数值. JDK1.6 中, jinfo 对于 Windows 平台功能仍然有很大的限制, 只提供了最基本的 - flag 选项.
jinfo 的命令格式如下:
jinfo [option] pid
jmap:Java 内存映像工具
jmap 命令用于生成堆转储快照(一般称为 heapdump 或者 dump 文件), 如果不是用 jmap 命令, 想要获取 Java 堆转储快照, 要有一些暴力手段, 用 - XX:HeapDumpOnOutOfMemoryError 参数, 可以让虚拟机在 OOM 异常出现之后自动生成 dump 文件, 通过 - XX:HeapDumpOnCtrlBreak 参数则
可以使用 [Ctrl]+[Break] 键让虚拟机生成 dump 文件, 又或者在 Linux 系统下通过 Kill -3 命令发送进程退出信号吓唬一下虚拟机, 也能拿到 dump 文件. jmap 的作用并不仅仅是为了获取 dump 文件, 它还可以查询 finalize 执行队列, java 堆和永久代的详细信息, 如空间使用率, 当前用的是哪种收集器等.
jmap 有不少功能在 Windows 平台下都是受限制的, 除了生成 dump 文件的 - dump 选项和用于查看每个类的实例, 空间占用统计的 - histo 选项在所有操作系统都提供外, 其余只能在 Linux/Solaris 下使用.
jmap 命令格式:
jmap [option] vmid
option 选项合法值与具体含义如下:
例子如下:
5.jhat: 虚拟机堆转储快照分析工具
jhat 命令与 jmap 搭配使用, 来分析 jmap 生成的堆转储快照. jhat 内置了一个微型的 HTTP/html 服务器, 生成 dump 文件的分析结果后, 可以在浏览器查看. 实际工作中, 如果没有别的工具可用, 一般不会用 jhat 分析 dump 文件的.
原因有二: 一是一般不会在部署应用程序的服务器上直接分析 dump 文件, 即使这样做, 也会尽量将 dump 文件复制到其他机器上进行分析, 因为分析工作是一个耗时并且消耗硬件资源的过程. 另外一个原因是 jhat 的分析功能相对于简陋,
后面会提到专业的工具 VisualVM, 以及专业分析 dump 的 Eclispe Memory Analyzer, 等工具.
6.jstack:Java 堆栈跟踪工具
jstack 命令用于生成虚拟机当前时刻的线程快照(一般称为 threaddump 或者 javacore 文件). 线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈集合, 生成线程快照的主要目的是定位线程出现长时间停顿的原因. 线程出现停顿的时候通过
jstack 来查看各个线程的调用堆栈, 就可以知道没有响应的线程到底在后台做些什么事情, 或者等待着什么资源
jstack 命令格式如下:
jstack [option] vmid
option 选项的合法值与具体含义如下:
例子如下:
在 JDK1.5 中, java.lang.Thread 类新增了一个 getAllStackTraces()方法用于获取虚拟机中所有线程的 StackTraceElement 对象. 使用这个方法可以通过简单的几行代码就完成了 jstack 的大部分功能. 在实际项目中不妨调用这个方法做个管理员页面, 可以随时使用浏览器
来查看线程堆栈, 例子如下:
- package hjc.test9b;
- import java.util.Map;
- /**
- * Created by cong on 2018/4/5.
- */
- public class Main {
- public static void main(String[] args) {
- Map<Thread, StackTraceElement[]> m = Thread.getAllStackTraces();
- for (Map.Entry<Thread, StackTraceElement[]> en : m.entrySet()){
- Thread t = en.getKey();
- StackTraceElement[] v = en.getValue();
- System.out.println("The Thread name is :" + t.getName());
- for (StackTraceElement s : v){
- System.err.println("\t" + s.toString());
- }
- }
- }
- }
运行结果如下:
7.JConsole:Java 监控与管理控制平台.
JConsole 是一种基于 JMX 的可视化监视, 管理工具. 通过 JDK/bin 目录下的 jconsole.exe 来启动 JConsole
双机她进去, 可以看到主界面包括概述, 内存, 线程, 类, VM 摘要, MBean6 个页面
对线程的监控例子如下:
死锁代码样例:
这段代码开了 200 个线程去分别计算 1+2 以及 2+1 的值, 造成死锁的原因是 Integer.valueOf()方法基于减少对象创建次数和节省内存的考虑,[-128,127]之间的数字会被缓存, 当 valueOf()方法传入参数在这个范围之内, 将直接返回缓存中的对象. 也就是说
代码中调用 200 次 Integer.valueOf()方法一共就返回了两个不同的对象. 假如在某个线程的两个 synchronized 块之间发生了一次线程切换, 那就会出现线程 A 等线程 B 持有的 Integer.valueOf(1), 线程 B 又等待着被线程 A 持有的 Integer.valueOf(2), 结果大家都跑不下去.
出现思索后, 点击 Jconsole 线程面板的检测到死锁的按钮, 将出现一个新的死锁标签. 如下图:
8.VisualVM: 多合一故障处理工具
VisualVM 可以做到:
1. 显示虚拟机继承以及进程的配置, 环境信息(jps,jinfo)
2. 监视应用程序的 CPU,GC, 堆, 方法区, 以及县城信息(jstack,jstat)
3.dump 以及分析堆转快照(jmap,jhat)
4. 方法级的程序运行性能分析, 找出被调用最多, 运行时间最长的方法.
5. 离线程序快照: 收集程序的运行时配置, 线程 dump, 内存 dump 等信息建立一个快照, 可以将快照发送开发者进行 BUG 反馈.
安装后, 打开如下:
来源: https://www.cnblogs.com/huangjuncong/p/8995333.html