学习环境,jdk1.8,windows7,内存16G。
1.工具学习
安装jdk时,在安装目录下的bin文件夹中有很多的相关的工具(**.exe),对于该工具的源码在lib文件中的tools.jar中的sun/tools中。在学习工具前,可以提前学习一下jvm相关的知识点。JVM笔记

2.常用的jdk命令
jps(java Process Status Tool):显示指定系统内所有的虚拟机进程
jstat(java Statistics Monitoring Tool):用于收集虚拟机各方面的运行数据
jinfo(Configuration info for java):显示虚拟机配置信息
jmap(Memory Map for java):生成虚拟机的内存转储快照
jhat(JVM Heap Dump Browser):用于分析heapdump文件,建立一个HTTP/Html服务器,使得在浏览器中分析
jstack(Stack Trace for java):显示虚拟机的线程快照
2.1 jps命令
作用是:列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main类, main()函数所在的类)名称以及进程的本地虚拟机唯一id(LVMID)。jdk使用频率最高的jdk命令行工具,因为其他的jdk工具大多数需要输入唯一ID确定监控的虚拟机进程。如果启动多个虚拟机进程,无法根据进程名定位时,需要使用jps确定。
命令格式:
jps [options] [hostid]
参数:
-q:显示进程id
-m:显示进程id,主类名称以及传入main的参数
-l:显示进程id,以及显示全类名
-v:显示进程ID,主类名称以及传入JVM的参数
-V:显示进程id,主类名称
[-mlvV]混合使用
常用的jdk工具(可视化)
2.2 jstat命令
作用:监视虚拟机各种运行状态信息,可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据
命令格式:
jstat [options cmid [interval] [count]]
参数的含义
1.options 表示用户希望查询的虚拟机信息,主要分为3类:类装载、垃圾收集、运行期编译状况,具体的选项如下:
-class:显示有关类加载器行为的统计信息
结果的含义:Loaded表示已加载的类数量 Bytes:加载的kb数
Unloaded:卸载的类数量 Bytes:卸载的KB数
Time:执行类加载和卸载花费的时间
-compiler:显示有关java HotSpot VM即时编译行为的统计信息
Compiled:执行的编译任务数 failed:编译任务失败数
Invalid:无效的编译任务数 Time:执行编译任务所花费的时间
FailedType:上次失败的编译的编译类型
FailedMethod上次失败的编译的类名和方法
-gc:显示有关垃圾收集堆行为的统计信息
-gccapacity:显示有关各个垃圾回收代容量及其响应空间的统计信息
-gccause:显示有关垃圾收集统计信息,以及上一次和当前垃圾收集事件的原因
-gcnew:显示新生代行为的统计信息
-gcnewcapacity:显示有关新生代大小及其相应空间的统计信息
-gcold:显示有关老年代行为的统计信息和元空间统计信息
-gcoldcapacity:显示有关老年代大小的统计信息
-gcmetacapacity:显示元空间大小的统计信息
-gcutil:显示有关垃圾收集统计信息
-printcompilation:显示JAVA Hotspot VM编译方法统计信息
2.vmid
如果是本地虚拟机进程,vmid和本地虚拟机唯一id是一致的
如果是远程虚拟机进程,vmid格式
protocol:lvmid[@hostname[:port]/servername]
3.interval
采样间隔,单位为秒s或者毫秒ms
单位是毫秒,必须传入正整数,设置后在指定的时间间隔产生输出。
4.count
要显示的样本数
2.3 jstat命令演示
public static void main(String[] args) throws IOException {
final int _1MB = 1024*1024;
byte[] b1 = new byte[2*_1MB];
System.out.println("1..");
System.in.read();
byte[] b2 = new byte[2*_1MB];
System.out.println("2..");
System.in.read();
byte[] b3 = new byte[2*_1MB];
System.out.println("3..");
System.in.read();
}
JVM参数
-Xms20M -Xmx20M -Xmn10M -xx:+UseSerialGC -XX:+PrintGCDetails -verbose:gc

分析:
s0c和s1c指的是幸存区容量的大小
s0u和s1u值得是幸存区使用的大小
EC 伊甸园区容量大小
EU 伊甸园区使用的大小
OC老年大容量
OU老年代使用
MC 元空间容量
MU 元空间使用
CCSC 压缩类空间的容量
CCSU 压缩类空间的使用
YGC youngGC次数
YGCT youngGC时间
FGC full gc 次数
FGCT full gc时间
GCT gc总时间
jstat -gcutil 端口号
参数的值表示的是占比(使用/容量)

程序执行一次垃圾回收后:

再使用jstat查看数据区信息,垃圾回收信息

2.4 jinfo命令
作用:实时的查看和调整虚拟机各项参数
命令格式:
jinfo [options]
参数解释options:
no option:输出全部的参数和系统的属性
-flag name :输出对应名称的参数
-flag [+|-]name:开启/关闭对应名称的参数
-flag name = value:设定对应名称的参数
-flags:输出全部的参数
-sysprops:输出系统属性
2.5 jinfo命令演示:
//运行程序后测试
public static void main(String[] args) throws IOException {
System.out.println("jinfo");
System.in.read();
}
jinfo指令联系

设置对转储文件位置为D的根目录

2.6 jmap
作用:可以生成java的dump文件,也可以查看堆内存对象信息、查看ClassLoader的信息以及finalizer队列
命令格式:jmap [options]
参数解释:
no option:不添加参数,查看进程的内存映像信息,类似于linux中的pmap
heap:显示java堆详细信息
histo[:live]:显示堆中对象的统计信息
clstats:打印类加载器信息
finalizerinfo:显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
dump:
:生成堆转储快照
2.7 jmap命令演示
jmap pid 查看进程的内存映像
jmap -heap pid 显示java堆详细信息
jmap -histo:live pid (或者jmap -histo pid)显示堆中对象的统计信息
jmap -clstats pid 打印类加载器信息
jamp -finalizerinfo pid 打印等待终结的对象信息
jmap -dump:live,format=b,file=D:\jmap.bin pid生成堆转储快照dump文件
部分指令显示截图:

类加载器信息

生成堆转储文件

2.8 jhat
作用:分析jmap生成的堆转储快照二进制文件,内置一个微型的http/HTML服务器,生成的dump文件的分析结果后,可以在浏览器中查看。
该工具分析是一个耗时且消耗硬件资源的过程,工具相对简陋,有更好的工具替换jhat,例如VisualVM,以及专业的dump分析Eclipse Memory Analyzer、IBM HeapAnalyzer等工具。
命令格式:jhat [options] 堆转储文件
参数解释[options]:
[-stack
] : 开关对象分配调用栈跟踪,如果分配位置信息在堆转储中不可用,则必须将此标志设置为false,默认设置为true [-refs
] :开关对象引用跟踪。默认为true,返回的指针是指向其他特定对象的对象,如反向链接或输入引用,会统计/计算堆中的所有对象 [-port
] :设置jhat HTTP server 的端口号。默认7000 [-exclude
] :指定对象查询时需要排除的数据成员列表文件。 [-baseline
] :指定一个基准堆转储。在两个heap dumps中有相同的object ID的对象会被标记为不是新的,其他对象被标记为新的。用于比较两个不同的堆转储文件。 [-debug
] :设置debug级别。0表示不输出调试信息,值越大表示输出越详细 [-version] :启动后显示版本信息就退出
jhat命令的使用:

2.9 jstack命令
作用:查找或导出java应用程序中线程堆栈信息
线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程死锁、死循环、长时间等待外部资源等。线程停顿时通过jstack来查看各个线程的调用堆栈,就可以知道响应的线程在后台执行什么事情,等待什么样的资源。java程序崩溃生成的core文件,jstack工具可以用来获取core文件的java stack和native stack的信息,从而可以轻松的知道java程序如何崩溃和在程序何处发生问题。
命令格式:
jstack [options] pid
options参数解释
-F:当线程挂起时,使用stack -l pid请求不被响应时,强制输出现场呢过堆栈
-l:除了堆栈外,显示关于锁的附加信息
-m:可以同时输出java以及c/c++的堆栈信息
2.10 jstack演示:
cpu占用过高,问题的排查流程:
1.使用Process Explorer工具,找到CPU占用率高的进程的id
2.右击该进程,查看属性,在thread选项卡中,找到cpu占用率高的线程id
3.把线程id转换成16进制
4.使用jstack -l pid查看进程的线程快照
5.在线程快照中使找到指定线程,并分析代码
jsatck查看死循环

jsatck查看IO阻塞

jsatck查看死锁
public static void test3() {
Object o1 = new Object();
Object o2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (o1) {
System.out.println("需要o2");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
System.out.println("Lock");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (o2) {
System.out.println("需要o1");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1) {
System.out.println("Lock");
}
}
});
t1.start();
t2.start();
}
使用命令: jstack -l pid

3.常用的jdk工具(可视化)
3.1 JConsole
作用:查看java应用程序的运行概况,监视垃圾收集器管理的虚拟机内存(堆和元空间)的变化趋势,以及监控程序内的线程。
启动JConsole,在控制台输入:Jconsole即可,寻找本地进程,再进去看界面页信息。显示的是整个虚拟机主要的运行数据概况,包括堆内存使用情况、线程、类、CPU使用情况的曲线图。

内存:
相当于命令行的jstat命令,用于监视垃圾收集器管理的虚拟机内存(堆和元空间)的变化趋势,这不仅包括堆内存的整体信息,更细化到伊甸区、幸存区、老年代的使用情况。同时包括非堆区,即元空间的使用情况,单机界面的执行GC可以强制应用程序进行一次Full GC
线程:
相当于命令行的jstack命令,遇到线程停顿的时候可以使用它来进行监控分析。JConsole显示了系统内的线程数量,并在屏幕下方,显示了程序中所有的线程,单机线程名称,便可查看线程的栈信息。
类:
显示系统装载和卸载的类数量。
VM摘要:
在VM摘要页面,JConsole显示了当前应用程序的运行环境。包括虚拟机类型,版本、堆信息以及虚拟机参数。相当于jinfo命令。
MBean:
MBean页面允许通过JConsole访问已经在MBean服务器注册的MBean对象。
3.2 Visual VM
作用:是jdk发布功能最强大的运行监视和故障处理程序,官网在VisualVM的软件说明中写上了”All-in-one”的字样,预示着其除了监视、故障处理外,还提供了很多其他方面的能力。
VisualVM是基于netBeans平台开发,因此具备可扩展性,通过VisualVM可以做到:
1.显示虚拟机进程以及进程的配置、环境信息(jps、jinfo)
2.监视应用程序的CPU、GC、堆、方法区、以及线程的信息(jstat、jstack)
3.dump以及分析堆转储快照(Jmap、jhat)
4.方法级的程序运行性能分析,找到被调用最多、运行时间最长的方法
5.离线程序快照,收集程序的运行时配置、线程dump、内存dump等信息建立一个快照,可以将快照开发者处进行bug反馈
使用:
1.在控制台输入:jvisualvm执行即可
2.安装插件:从主菜单中选择工具>插件,可在可用插件标签中,选中该插件的安装复选框,单机安装,逐步完成插件安装程序
jvisualvm的测试
测试类设置:
public class JvmDemoVisiual03 {
public static void main(String[] args) throws Exception {
test1();
System.in.read();
}
public static void test1() throws InterruptedException {
List<Student> list = new ArrayList<>();
for (int i = 0; i <100 ; i++) {
Thread.sleep(1000);
list.add(new Student());
}
}
}
class Student{
private byte[] big = new byte[5*1024*1024];//5M
}
输入命令,显示可视化界面

4.内存分析与线程分析
4.1 监视
监视是一种用来查看应用程序运行时行为的一般方法,通常会有多个视图分别实时的显示CPU使用情况、内存使用情况、线程状态以及其他一些有用的信息,以便用户能很快发现问题的关键所在。
4.2 转储
性能分析工具从内存中获取当前状态数据并存储到文件用于静态的性能分析。java程序是通过在启动java程序时添加适当的条件参数来出发转储操作。其包括以下三种:
1.系统转储:JVM生成的本地系统的转储,又称作核心转储,一般的,系统转储数据量大,需要平台相关的工具去分析,如windows上的windbg和linux上的db。
2.java转储:jvm内部生成的格式化后的数据,包括线程信息,类的加载信息以及堆的统计数据。通常也检查死锁
3.堆转储:jvm将所有对象的堆内容存储到文件
4.3 快照
应用程序启动后,性能分析工具开始收集各种运行时的数据,其中一些数据直接显示在监视器视图中,而另外大部分数据被保存在内部,知道用户要求获取快照,基于这些保存的数据的统计信息才被显示出来。快照包含了应用程序在一段时间内的执行信息,通常有cpu快照和内存快照两种类型。
4.4 性能分析
性能分析是通过收集程序运行时的执行数据来帮助开发人员定位需要被优化的部分,从而提高程序的运行速度或是内存使用效率,主要有三个方面:
1.CPU性能分析:CPU性能分析的主要目的是统计函数的调用情况及执行情况,或者更简单的情况就是统计应用程序的cpu使用情况。通常有cpu监视和cpu快照两种方式来显示cpu性能分析结果。
2.内存性能分析:内存性能分析的主要目的是通过统计内存使用情况检测可能存在的内存泄露问题及确定优化内存使用的方向。通常有内存监视和内存快照两种方式显示内存性能分析结果。
3.线程性能分析:线程性能分析主要用于多线程应用程序中确定内存问题的所在。一般包括线程状态的变化情况,死锁情况和某个线程在线程生命周期内状态的分布情况等。