《深入理解java虚拟机 笔记》
第四章 虚拟机性能监控与故障处理工具
使用适当的虚拟机监控和分析工具可以加快我们分析运行日志、异常堆栈、GC 日志、线程快照(threaddump / javacore 文件)、堆转储快照(headdump / hprof 文件)等数据,定位解决问题的速度。
常用的虚拟机性能监控JDK命令行工具
每逢 JDK 个更新版本之时,bin 目录下命令行工具的数量和功能总会不知不觉地增加和增强。这些命令行工具大多数是 jdk/lib/tools.jar 类库的一层薄包装而已,它们主要的功能代码是在 tools 类库中实现的。
jps: 显示所有虚拟机进程
jps 命令格式:
- jps [options] [hostid]
jps 可以通过 RMI协议查询开启了 RMI 服务器的远程虚拟机进程状态,hostid 为 RMI 注册表中注册的主机名。
使用样例:
使用样例:可以查看虚拟机启动时显示指定的参数列表
jstat:监视虚拟机各种运行状态信息
jstat(JVM Statistics Monitoring Tool)是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据,在没有 GUI 图形界面,只提供纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。jstat监视选项众多,需要用时再具体查找指定的参数选项。
使用样例:这里通过一台刚刚启动的 tomcat 服务器的内存状况的例子来演示如何查看监视结果。监视参数与输出结果如下图所示。
查询结果表明:这台服务器的新生代 Eden 区(E,表示 Eden)使用了 7.73% 的空间,两个 Survivor 区(S0、S1,表示 Survivor0、Survivor1)里面都是空的,老年代(O,表示 Old)和永久代(M,表示 Permanent)则分别使用了 33.34% 和 98.05 的空间。程序运行以来共发生 Minor GC(YGC,表示 Young GC)13 次,总耗时 0.152 秒,发生 Full GC(FGC,表示 Full GC)2此,Full GC 总好耗时(FGCT,表示 Full GC Time)为 0.175秒,所有 GC 总耗时(GCT,表示 GC Time)为 0.327秒。
jmap:生成堆转储快照(内存映像工具)
jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为 heapdump 或 dump 文件)。如果不使用 jmap 命令,要想获取 Java 堆转储快照,还有一些比较“暴力”的手段:譬如前面用过的-XX:+HeapDumpOnOutOfMemoryError 参数,可以让虚拟机在 OOM 异常出现之后自动生成 dump 文件,通过 -XX:+HeapDumpOnCtrlBreak 参数则可以使用 [Ctrl]+[Break] 键让虚拟机生成 dump 文件,又或者再 Linux 系统下通过 Kill -3 命令发送进程退出信息“吓唬”一下虚拟机,也能拿到 dump 文件。
使用样例:先启动一个java程序Server,输入jmap后有使用提示。
jstack:Java 线程堆栈跟踪工具
jstack主要用来查看某个Java进程内的线程堆栈信息。jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为 threaddump 或者 javacore 文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的常见原因。线程出现停顿的时候通过 jstack 来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做些什么事情,或者等待着什么资源。
在Windows下建议用VisualVM,在linux下可用该工具。
jstack 命令格式:
jstack [option] pid
jstack [option] executable core
jstack [option] [server-id@]remote-hostname-or-ip
参数:
虚拟机性能监控JDK可视化工具
JConsole:Java 监视与管理控制台
启动JDK/bin目录下“jconsole.exe"启动JConsole后,连接需要监视的虚拟机进程。
运行演示例子:
public class TestJConsole {
/*
* 内存占位符对象,一个OOMObject大约64KB
* */
static class OOMObject{
public byte[] placeholder = new byte[64*1024];
}
public static void fillHeap(int num) throws InterruptedException{
List<OOMObject> list = new ArrayList<OOMObject>();
for(int i = 0; i < num; i++)
{
Thread.sleep(500);
list.add(new OOMObject());
}
System.gc();
}
public static void main(String[] args) throws InterruptedException {
fillHeap(1000);
}
}
一个OOMObject大约64KB,list 总共会有64M左右。可以看出Eden空间分配为16384K,由于没有设置-XX:SurvivorRadio参数,所以Eden与Survivor空间比例为默认值8:1,所以整个新生代的空间大约为:16384K*125%=20480K。每当Eden空间使用到16384K时,触发一次GC,其中总共触发了6次,最后一次由于程序运行结束。
前5次的GC,使16M的数据从新生代的Eden转移至老年代中,于是老年代的数据增长了5次。
可以看出堆中总内存变化,也发生了6次GC,每次GC堆都会清除一些无用的数据。
GC中,PS Scavenge’, 收集 = 6, 总花费时间 = 0.048 秒。
VisualVM:多合一故障处理工具
VisualVM(All-in-One Java Troubleshooting Tool)是到目前为止随 JDK 发布的功能最强大的运行监视和故障处理程序,并且可以预见在未来一段时间内都是官方主力发展的虚拟机故障处理工具。测试代码:
public class TestVisualVMTool {
public static void createBusyThread() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"is running");
// TODO Auto-generated method stub
while(true)
;
}
},"testBusyThread");
thread.start();
}
/*
* 线程锁等待演示
* */
public static void createLockThread(final Object lock)
{
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
},"testLockThread");
thread.start();
}
public static void main(String[] args) throws IOException {
BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
bReader.readLine();
createBusyThread();
bReader.readLine();
Object object = new Object();
createLockThread(object);
}
}
运行后:上面的jconsole工具仍然可以用
发现main方法的堆跟踪中,main线程是runnable。
java.io.FileInputStream.readBytes(Native Method)
java.io.FileInputStream.read(Unknown Source)
java.io.BufferedInputStream.read1(Unknown Source)
java.io.BufferedInputStream.read(Unknown Source)
main线程在等待java.io.FileInputStream.readBytes,所以在eclipse中输入后出现testBusyThread和testLockThread线程,并且可以看出testLockThread处于等待状态。
用visualVM也可以看出,testLockThread处于等待状态,而main线程已经执行完毕。
点击线程dump,也可查看具体线程的堆信息。
visualVM还有强大的实时分析CPU和内存功能,点击profiling。CPU分析会统计每个方法执行次数、执行耗时;如果是内存分析,会统计每个方法关联的对象以及这些对象所占的空间。
visualVM还有很强大的功能BTrace,可以动态日志跟踪。