虚拟机性能监控与故障处理
1.jdk命令行工具
lib/tool.jar包
1.jps:虚拟机进程状况工具
jps [options] [hostid]
JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。(类似UNIX的 ps命令),查看进程快照。列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)名称以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID),对于本地虚拟机进程来说,LVMID与操作系统的进程ID(Process Identifier,PID)是一致的。
-q :只输出LVMID-l :输出主类的全名,如果进程执行的是Jar包,输出Jar路径-v :输出虚拟机进程启动时JVM参数-m:输出虚拟机进程启动时,传递给主类main()函数的参数
2.jstat:虚拟机统计信息监视工具
JVM Statistics Monitoring Tool,用于监视虚拟机各种运行状态信息。显示本地或远程虚拟机进程中的类装载,内存,垃圾回收,JIT编译等运行数据。jstat [ option vmid [ interval[s|ms] [count] ] ]如果是本地虚拟机进程,VMID与LVMID一致,interval表示查询间隔,count表示查询次数。如:jstat -gc 2764 250 20 表示查询2764进程 的垃圾回收情况,没250毫秒查询一次,共查询20次。
option代表查询的虚拟机信息:类装载,垃圾回收,运行期编译状态。
(S0,S1表示Survivor0,Survivor1),E表示Eden区使用55%,O表示Old老年代使用60%,P(Permanent)永久代使用99.74%。YGC(Young GC)及Minor GC 52次,耗时0.275s。FGC(Full GC) 4次,总耗时0.458秒。GCT(GC Time)0.733秒。
3.jinfo:java配置信息工具
jinfo(Configuration Info for Java),实时查看和调整虚拟机各项参数。jinfo -flag [+|-] name 或jinfo -flag name = vlaue来修改部分运行期参数。
4.jmap:java内存映像工具
Memory Map For Java,生成堆存储快照。不仅可以获取dump文件,还可以查询finalize执行队列,Java堆和永久代的详细信息,如空间使用率,当前使用的哪种收集器。jmap [ option ] vmid
输出dump快照文件。
5.jhat:虚拟机堆转储快照分析工具
JVM Heap Analysis Tool,分析jmap生成的堆转储快照。jhat内置以一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,可以在浏览器中查看。
访问:localhost:7000/
6.jstack:java堆栈跟踪工具
Stack Trace For Java,生成虚拟机当前时刻的线程快照,即当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如死锁,死循环,请求外部资源导致的长时间等待等。在线程停顿时,通过jstack来查看各个线程的调用堆栈,就可知道没有响应的线程在后台做什么事情,或等待什么资源。jstack [ option ] vmid-F : 正常输出的请求不被响应时,强制输出线程堆栈-l :除堆栈外,显示关于锁的附加信息-m:如果调用到本地方法的话,显示C/C++的堆栈
java.lang.Thread类有一个getAllStackTraces()方法,可获取虚拟机中所有线程的StackTraceElement对象。可通过在服务器上添加一个jsp页面来通过浏览器查看虚拟机线程状态<%@ page import="java.util.Map" pageEncoding="utf-8"%> <html> <head> <title>服务器线程信息</title> </head> <body> <pre> <% for(Map.Entry<Thread,StackTraceElement[]> stackTrace:Thread.getAllStackTraces().entrySet()){ Thread thread = (Thread)stackTrace.getKey(); StackTraceElement[] stack = (StackTraceElement[])stackTrace.getValue(); if(thread.equals(Thread.currentThread())){ continue; } out.print("\n线程:"+thread.getName()+"\n"); for(StackTraceElement element:stack){ out.print("\t"+element+"\n"); } } %> </pre> </body> </html>
2.jdk可视化工具
1.jconsole:java监视与管理控制台
Java Monitoring and Management Console是一种基于JMX的可视化监视,管理工具。1.启动JConsole
jconsole.exe
2.内存监控
相当于jstat命令。监视虚拟机内存(堆和永久带)的变化趋势。
测试代码:
/** * VM args:-Xms100m -Xmx100m -XX:+UseSerialGC * * @author lss * */ public class JConsoleTest { static class OOMObject { public byte[] placeholder = new byte[64 * 1024]; } public static void fillHeap(int num) throws InterruptedException { List<OOMObject> list = new ArrayList<JConsoleTest.OOMObject>(); for (int i = 0; i < num; i++) { Thread.sleep(50); // 每50毫秒向内存中添加64KB的数据 list.add(new OOMObject()); } System.gc();//新生代Eden和survivor区全部回收(对象转移到老年代),由于对象都被list引用,老年代中对象不回收 } public static void main(String[] args) throws Exception { fillHeap(1000); System.out.println("hehe"); } }
新生代:(27/8)*10 = 34MB
老年代:66MB
对上面代码进行断点调试可以看出:新生代Eden区大小为27MB,由此可算出 整个新生代内存大小为:(27/8)*10 = 34MB
执行System.gc()后,由于对象都被list引用,所以新生代清空,对象都进入老年代,老年代内存没有回收。
3.线程监控
相当于jstack命令。
测试代码:
/** * 线程死循环 */ public static void createBusyThread() { Thread thread = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while (true) ; } }, "testBusyThread"); thread.start(); } /** * 线程死锁 * * @param lock */ public static void createLockThread(final Object lock) { Thread thread = new Thread(new Runnable() { @Override public void run() { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "testLockThread"); thread.start(); } public static void main(String[] args) throws Exception { // fillHeap(1000); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 控制台第一次输入,创建一个死循环的线程 br.readLine(); createBusyThread(); // 控制台第二次输入,创建一个死锁的线程 br.readLine(); Object obj = new Object(); createLockThread(obj); }
main函数中,readBytes方法被执行,但是没有检测到输入时,会立刻归还执行令牌,CPU资源消耗小
当输入内容,调用testBusyThread线程时,这个线程执行会停留在while循环处,由于死循环,线程一直占用着CPU资源,不会归还线程执行令牌。会消耗较多的CPU资源。
当再次输入,执行testLockThread线程时,线程在等待lock对象的notify,等待时处于WAITIING状态,线程只有被唤醒才会被分配执行时间。
死锁样例:
Integer.valueOf()使用了响元设计模式,对于[-128,127]之间的数会进行缓存,当调用valueOf()方法时,如果在范围内,就会直接返回缓存中的对象。上面代码调用了200次Integer.valueOf()方法,但一共就返回了两个不同的对象。public class SynAddRunable implements Runnable { int a, b; public SynAddRunable(int a, int b) { this.a = a; this.b = b; } @Override public void run() { synchronized (Integer.valueOf(a)) { synchronized (Integer.valueOf(b)) { System.out.println(a + b); } } } public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(new SynAddRunable(1, 2)); new Thread(new SynAddRunable(2, 1)); } } }
2.visualvm:多合一故障处理工具
All-in-One Java Troubleshooting Tool,对应用程序的实际性能的影响很小,使得它可以直接应用在生产环境中。基于NetBeans平台开发,具备插件扩展功能的特性。1.VisualVM 兼容范围与插件安装
- 显示虚拟机进程以及进程的配置,环境信息(jps,jinfo)。
- 监视应用程序的CPU,GC,堆,方法区以及线程的信息(jstat,jstack)。
- 方法级的程序运行性能分析,找出被调用最多,运行时间最长的方法。
- 离线程序快照:收集程序的运行时配置,线程dump,内存dump等信息建立一个快照
插件中心地址:http://visualvm.java.net/pluginscenters.html2.性能分析
Profiler页签,选择"CPU"和"内存"按钮中的一个进行监控。CPU分析:统计每个方法的执行次数,执行耗时内存分析:统计每个方法关联的对象数以及这些对象所占的空间