调优命令
当我们的程序有卡顿,oom,死锁等等各种情况我们如果是自己写的代码,还能大概清楚出问题的代码在哪儿,如果你作为项目经理,具体业务代码并不清楚,要查找这些问题就需要jvm调优工具,当然也可以用以装逼。。。好了,那么我们一起来看下如何使用jvm的这些命令
前置条件,本地开启一个java项目,什么项目都可以
JPS
jps命令语法:jps [options ] [ hostid ] 参数可以不写
[options]参数 :
-q:仅输出进程 id,不包括classname,jar name,arguments in main method
-m:输出main method的参数
-l:输出彻底的包名,应用主类名,jar的彻底路径名
-v:输出jvm参数
-V:输出经过flag文件传递到JVM中的参数(.hotspotrc文件或-XX:Flags=所指定的文件
-Joption:传递参数到vm,例如:-J-Xms512m
[hostid]:
[protocol:][[//]hostname][:port][/servername]web
协议 主机名 端口 服务名称 (可以远程查看其他服务器)
使用:
1. 打开cmd命令窗口,输入jps 查看当前运行的 java 进程ID 和 启动类的名称
如果输入没有任何反应:(没问题的往下继续)
a.打开文件地址栏转到:%TMP%
b.找到 hsperfdata_user(user是当前电脑登录用户名)文件夹
c. 右键属性》安全》找到对应用户,编辑》完全控制,应用后
d. 再运行java程序,看下里面有没有生成文件,又就可以再jps
2. 其他参数自行测试
ps: 这个参数最常用的作用应该是查询当前java进程id(本人使用如此)
JMAP
jmap命令是一个可以输出所有内存中对象的工具,也可以将VM 中的heap,以二进制输出成文本。
命令格式:
jmap [option] <pid> (to connect to running process) 连接到正在运行的进程
jmap [option] <executable <core> (to connect to a core file) 连接到核心文件
jmap [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server) 连接到远程调试服务
1. -heap 打印heap的概要信息,GC使用的算法,heap(堆)的配置及JVM堆内存的使用情况
例: jmap -heap pid (附翻译)
2. -finalizerinfo 打印正等候回收的对象的信息
例: jmap -finalizerinfo pid (附翻译) 现在是0个待回收
3. -dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件
例:jmap -dump:live,format=b,file=test.txt pid
输出到了当前目录(这个文件打开看不懂,后面我们用jvisualvm去分析就好了)
4. -histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量。
例:jmap -histo:live pid (截图部分,太多了,一般不太会用这个查看,不好观察)
JSTACK
jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息
jstack [-F/-l/-m] pid 一般用来分析线程死锁和cpu高得情况
-F:当正常输出的请求不被响应时,强制输出线程堆栈。
-l:除堆栈外,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况
-m:如果调用到本地方法的话,可以显示C/C++的堆栈
模拟线程死锁:
private static Object a = new Object();
private static Object b = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (a){
try {
System.out.println("a对象上锁");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b){
System.out.println("b对象上锁");
}
}
}).start();
new Thread(() -> {
synchronized (b){
try {
System.out.println("b线程对b对象上锁");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a){
System.out.println("b线程对a对象上锁");
}
}
}).start();
}
出现死锁,先找到pid用 jstack -l pid查找死锁代码
找到一个死锁,对应得两个线程以及代码位置TestController.java:行数
cpu高 只需要一个死循环让cpu不停执行计算就可以实现
找到cpu使用最高得pid ,用jstack查找到对应线程,就能找到造成cpu高使用得代码
JSTAT
垃圾回收使用统计
堆内存统计
jstat -gccapacity pid
新生代回收情况
jstat -gcnew pid
老年代回收统计
jstat -gcold pid
元空间回收统计
jstat -gcmetacapacity pid
堆空间百分比统计
jstat -gcutil pid
jstat 是做jvm调优关键的命令,用这个命令我们可以分析出很多的问题:
年轻代对象增长的速率
可以执行命令 jstat -gc pid 1000 10 (每隔1秒执行1次命令,共执行10次),通过观察EU(eden区的使用)来估算每秒eden大概新增多少对象,如果系统负载不高,可以把频率1秒换成1分钟,甚至10分钟来观察整体情况。注意,一般系统可能有高峰期和日常期,所以需要在不同的时间分别估算不同情况下对象增长速率。
调优也不是一蹴而就的,不是说你查看了各种参数一顿分析然后调整参数就可以搞定了,这个是循序渐进的,再厉害的人也不可能一上来就能准确的说到问题点,分析只是找方向,经验越多,方向就会更正确,找问题就会更快速,实践才能检测真理
调优工具
调优工具就是把上面的命令封装了,然后变成可视化的操作,方便我们使用
jvisualvm
java自带的一个jvm调优工具,使用也很简单,在自己的jdk安装目录里面就能找到
jdk/bin/jvisualvm.exe打开就好
默认监控本地所欲的java运行程序,其实应该就是上面的命令的可视化操作版本,也支持远程
稍微看下:
随便点开一个java程序
当前运行jvm参数,监控cpu,线程等等自行操作
还可以把我们前面导出的test.txt放入查看:
点击文件》装入》记得选择堆 Dump》选择文件打开
可以看到,前面提到的文件就是查看当前的实例一些东西,查大量对象的时候经常使用,比如一个程序一直在创建对象,也没有回收,这个就能够找到是谁
ps: 一般不用 jmap 去查询 ,在监控里面点击 堆Dump
Arthas
阿里旗下的调优工具,没有使用过,据说挺好用,记录一下,以后可能会使用
api: https://alibaba.github.io/arthas
GC日志分析
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:D:\gc-%t.log
空的spring boot项目,没啥特别多的内容稍微分析下一些东西
上面的是参数,没啥特别的,基本都默认
2. Full GC 是一次full gc,括号里是gc的原因, PSYoungGen是年轻代的GC,ParOldGen是老年代的GC,Metaspace是元空间的GC(本次Full GC 原因就是元空间小了,默认21M不够)
其他原因导致的Full GC就对应处理