一篇文章教你用Java使用JVM工具检测问题
目录
- 1.jps
- 2.jstat
- 3.jinfo
- 4.jstack
- a.死循环案例
- b.等待输入
- c.死锁
- 5.jconsole
- 6.jvisualvm
- 总结
1.jps
显示运行程序的进程、编码、主类目录信息
public class Demo01 { /** * jps : 显示进程ID,主类名称 * jps -v: 显示进程ID,主类名称以及详细编码信息 * jps -l:显示进程ID,主类目录 * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { System.out.println("jps"); System.in.read(); } }
2.jstat
监视虛拟机各种运行状态信息,显示本地或者是远程虚拟机进程中的类装载内存、垃圾收集、编译等运行数据
public class Demo01 { /** * jstat -gc 18912 500 10 每隔500毫米打印10 次gc信息 * * jstat -class 18912 监视JVM类装载、卸载数量,总空间、类装载所耗费时间 * Loaded:已加载class类的数量 * Bytes:加载的kb内存空间数 * Unloaded:卸载class类数量 * Bytes:卸载的kb内存空间数 * Time: 执行 类加载和卸载操作所花费的时 * * jstat -compiler 18912 jvm编译类耗时操作 * Compiled:执行的编译任务次数 * Failed: 编译任务数失败 * Invalid: 无效的编译任务 * Time: 执行编译任务耗时 * FailedType: 编译失败的类型 * FailedMethod: 编译失败的类名 和 方法名 * @param args * @throws IOException */ public static void main(String[] args) throws IOException { System.out.println("jstat"); System.in.read(); } }
关于堆区命名规范,c-结尾空间,u-被使用空间 , t-回收时间
package com.qfedu.fmmall.test; import java.io.IOException; public class Demo03 { // Xms20m -Xmx20m -Xmn10m -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc /** jstat -gc 16944 * * 空间容量(kb) * 幸存者0 幸存者0被使用 伊甸园 伊甸园被使用 老年代 老年代被使用 元空间 被使用 压缩类 使用压缩类 * S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU * 10752.0 10752.0 0.0 0.0 65024.0 9865.8 173568.0 0.0 4480.0 770.3 384.0 75.9 * * 新生代垃圾回收数量 新生代垃圾回收时间 总垃圾回收时间 * YGC YGCT FGC FGCT GCT * 0 0.000 0 0.000 0.000 * * jstat -gcutil 16944 显示使用百分比 * * gcutil 项:垃级饮集统计信 * SO:幸存者空间 0利用率占该空间当前容量的分比 * S1:幸存者空间 1利用率占空间当前容量的分比 * E: Eden空间 利用率占空间当前容量的百分 * 0: 老年代 利用率占空间当前容量的百分比 * M: 元空间 利用率占空间当前容量的百分比 * CCS: 压缩的类空间初用率以百分比 * YGC:新生代GC事件的数量 * YGCT:新生代垃级回收时问 * FGC: 完整GC事件的数量 * FGCT: 完整的拉级收集时问 * GCT: 总拉扱收集时问 * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { final int _1mb = 1024 * 1024; byte[] b1 = new byte[2 * _1mb]; System.out.println("_1mb阻塞"); System.in.read(); byte[] b2 = new byte[2 * _1mb]; System.out.println("_2mb阻塞"); System.in.read(); byte[] b3 = new byte[2 * _1mb]; System.out.println("_3mb阻塞"); System.in.read(); } }
3.jinfo
3516 打印jvm系统参数
4.jstack
检测程序中的问题
jstack -l 19224
package com.qfedu.fmmall.test; import java.io.IOException; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Demo02 { public static void main(String[] args) throws IOException { // test1(); // test2(); test3(); } // 死循环 private static void test1() { while (true) { } } // 等待输入 private static void test2() throws IOException { System.out.println("jstat"); System.in.read(); } public static void test3() { Lock lock1 = new ReentrantLock(); Lock lock2 = new ReentrantLock(); new Thread(() -> { try { lock1.lock(); Thread.sleep(100); lock2.lock(); }catch (InterruptedException e) { e.printStackTrace(); } },"lock1").start(); new Thread(() -> { try { lock2.lock(); Thread.sleep(100); lock1.lock(); }catch (InterruptedException e) { e.printStackTrace(); } },"lock2").start(); } }
a.死循环案例
在liunx系统通过ps 根据进程 找到线程id,转换成转换成16进制。
死循环处于运行状态:RUNNABLE
b.等待输入
c.死锁
Found 1 deadlock. 发现一个死锁
5.jconsole
图形化监测程序的内存和线程变化等信息
死循环观察CPU很高
程序正常变化
检测死锁
6.jvisualvm
命令观察内存变化,还可以连接远程
堆内存变化
观察每个对象内存大小
每个线程CPU时间
检测到死锁
Liunx 用命令行多
详细介绍工具使用
版本是Java JDK1.8测试
真实项目体验,一开始启动测试
ed区内存300-400之间,JVM就自动执行了一次垃圾回收ed区,移到老年区
老年代是大对象连续存活的字符串,有没有那种可能,直接创建这种对象到老年代,避免内存复制和CPU开销,就像预编译一样,提前编译好等待被调用。
根据时间点看,GC回收一次ed区,大对象移到老年区,CPU飙升到百分之3,这得看机器CPU
总结
性能分析是通过收集程序运行时的执行数据来帮助开发人员定位程序需要被优化的部分,从而提高程序的运行速度或是内存使用效率,主要有以下三个方面CPU性能分析:
CPU性能分析
主要是统计函数的调用情况及执行时间,或者更简单的情況就是统计应用程序的CPU使用情况。通常有CPU监视和CPU快照两种方式来显示CPU性能分析結果.
内存性能分析
主要目的是通过统计内存使用情况检则可能存在的内存泄露问题及确定优化内存使用的方向。通常有内存监视和内存快照两种方式来量示内存性能分析结果。
线程性能分析
主要用于在多线程应用程序中确定内存的可题所在。一般包括线程的状态变化情况,死锁情和某个线程在线程生命期内状态的分布情况等
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!