JVM调优与线上问题监控工具安利
JVM调优与线上问题监控工具
首先命令行输入java -version,查看本机的Java版本信息以及JVM相关信息
可以看到的Java8,HotSpot虚拟机,Client模式启动,混合编译模式
XXX>java -version
java version "1.8.0_251"
Java(TM) SE Runtime Environment (build 1.8.0_251-b08)
Java HotSpot(TM) Client VM (build 25.251-b08, mixed mode)
JVM运行参数
JVM的运行参数总的来说可以分为三类:
标准参数:
- -help
- -version
- -server、-client
-server、-client 是设置JVM的运行模式的参数。JVM启动会根据硬件与操作系统自动选择运行模式:
- 32位系统如果是Windows,无论其余硬件配置如何,都默认client模式,其余操作系统如果是2G以上内存并且有2个以上CPU,默认是server模式启动。
- 64位操作系统默认server模式,不支持client
之前在做GC测试的时候也介绍过,这两种运行模式的区别在于:
- server模式启动时,堆空间可能默认大一点,JDK9以前默认是UseParallelGC,JDK9以后是UseG1GC。server模式启动慢,运行快
- client模式初始化堆空间小,默认是UseSerialGC。client模式下,JVM启动速度更快,但是运行速度慢
-X参数(非标准参数),不同JVM版本可能不同。可以在命令行使用java -X命令查看。
- -Xint、-Xcomp、-Xmixed,这三个参数是JVM启动时的编译模式,默认是mixed混合模式
-Xint:interpreted mode,解释器模式。编译与运行同时进行,在编译Java程序的时候一边编译一边执行,编译多少执行多少
-Xcomp:compile mode,编译模式。JVM在第一次使用时,会把所有的字节码编译成本地代码,即一次性编译完再使用,并且没有启用JIT编译器
-Xmixed:混合模式,解释器模式与编译模式混合使用,由JVM自己决定。
- …
-XX参数(非标准参数,使用频率较高),主要用于jvm调优与debug操作。-XX参数使用有两种方式:
-
一种是非boolean类型,即key-value
格式是-XX:key=value,如:
-XX:newRatio=1
-
一种是boolean类型
格式是-XX:[±],+表示启用,-表示禁用。如:
-XX:+UseSerialGC
JDK四个调优工具
jinfo
jinfo是JDK自带的查看JVM配置参数的工具。
查看所有的JVM配置参数:
jinfo -flags [pid]
如:
XXX> jinfo -flags 15628
Attaching to process ID 15628, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 25.251-b08
Non-default VM flags: -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote -XX:InitialHeapSize=16777216 -XX:+ManagementServer -XX:MaxHeapSize=268435456 -XX:MaxNewSize=89456640 -XX:MinHeapDeltaBytes=131072 -XX:NewSize=5570560 -XX:OldSize=11206656 -XX:TieredStopAtLevel=1 -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation
Command line: ....
如果只想查看单个:
jinfo -flag <name> [pid]
jstak
jstak命令可以查看编译统计,GC发生次数,以及加载的类数量。命令格式:
jstat -<option> [-t] [-h<lines>] <vmid> [<间隔时间/ms> [<查询次数>]]
如查看编译统计:
XXX> jstat -compiler 18100
Compiled Failed Invalid Time FailedType FailedMethod
126 0 0 0.06 0
查看加载类数量:
XXX> jstat -class 18100
Loaded Bytes Unloaded Bytes Time
1365 1350.2 0
查看GC次数:
XXX> jstat -gc 18100
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
512.0 512.0 438.4 0.0 4416.0 2694.9 10944.0 899.3 4416.0 4309.8 0.0 0.0 2 0.006 0 0.000 0.006
S0C:survivor0区总共大小;S0U:survivor0区已用大小
S1C:survivor1区总共大小;S1U:survivor1区已用大小
EC:Eden区总大小;EU:Eden区已用大小
OC:老年代总大小;OU:老年代已用大小
MC:元空间总大小;MU:元空间已用大小
CCSC:压缩类空间容量 ;CCSU:压缩类已用空间大小
YGC:Minor GC/Young GC的次数;YGCT:Minor GC/Young GC停顿时间
FGC:FullGC次数;FGCT:FullGC停顿时间
GCT:GC总停顿时间
jmap
当前程序堆使用情况,命令格式:
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)
jmap -heap
查看当前程序的堆情况,命令格式:
jmap -heap [pid]
jmap -histo
查看内存中对象数量及大小,命令格式:
jmap -histo:live [pid] | more 查看活跃对象,去掉live就是查看所有对象
jamp -dump
将当前内存的情况dump以二进制格式输出到文件,然后再配合日志分析工具进行分析,命令格式:
jmap -dump:format=b,file=dumpFileName
dump文件分析工具
jhat
我们可以利用jhat工具分析查看dump文件
MAT
除了jhat,我们也可以使用MAT,Memory Analyzer Tool,一个功能丰富的堆分析工具,可以帮忙查找内存泄露等问题,并可以通过报表的形式直观的看到那些对象在阻止垃圾回收,比如这样:
jstack
打印所有线程及其状态,是用来分析死锁的利器
在https://blog.csdn.net/qq_20952591/article/details/121428062,死锁的这一节也介绍过,这里就不再介绍了
监控工具
JVisualVM
JDK自带的性能检测工具,路径在%JAVA_HOME%/bin下面,是个JVM性能监控神器,功能包括:
- 监控本地和远程的JAVA进程,包括监控内存、线程、方法执行时间
- 对堆内存进行dump、快照
- 性能可视化分析
- 安装插件对堆外内存进行分析(我用Buffer Pool)
- …
Btrace
Btrace是一种安全、动态跟踪分析一个运行中的Java应用程序的工具。 BTrace动态地向目标应用程序的字节码注入追踪代码(字节码追踪),这些追踪字节码追踪代码使用Java语言表达,也就是BTrace的脚本。
安装btrace后需编写btrace脚本,功能包括:
对生产环境下的代码进行监控调试,比如获取生产环境下某个方法的参数、返回值、异常、执行的行号等等。(Arthas也可以做,个人认为Arthas更牛逼点)
github:https://github.com/btraceio/btrace
Arthas
Arthas是阿里巴巴开源的一个性能监控神器,可以用来做:
1.线上修改代码(比如线上出bug了,但是忘记在关键地方输出日志,这个时候可以利用arthas的reset命令来增强类)
2.查看系统运行状况
3.监控JVM实时状况
4.定位应用热点,生成火焰图
5.监控指定方法的数据统计与观测
6.死锁监控
…
官方使用文档:https://arthas.aliyun.com/doc/
GC日志分析
GC参数设置
GC日志相关参数共一下几个:
-XX:+PrintGC:输出GC日志
-XX:+PrintGCDetails:输出GC详细日志
-XX:+PrintGCTimeStamps:输出GC的时间,这个时间是JMV启动时间偏移量
-XX:+PrintGCDateStamps:输出GC时间,
-XX:+PrintHeapAtGC:在GC前后打印出堆的详细信息
-Xloggc:将GC日志输出到指定文件
GC日志分析工具
GCEasy网站
我们可以将GC日志文件上传到https://gceasy.io/,GCEasy官网去分析
我的测试代码(是我之前测试软连接的测试代码,就是不断产生大对象):
private static final int _4MB = 4 * 1024 * 1024;
@Test
public void softReference() throws InterruptedException {
System.out.println("=======================begin===============");
// Thread.sleep(50000);
List<SoftReference<byte[]>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
System.out.println("==================i " + i +
"insert begin=======================");
SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);
System.out.println("=======================this is i " + i + " " + ref.get()+
"=======================");
list.add(ref);
System.out.println("list = " + list.stream().map(SoftReference::get).collect(Collectors.toList()));
}
System.out.println("=======================循环结束=============");
System.gc();
System.out.println("list = " + list.stream().map(SoftReference::get).collect(Collectors.toList()));
}
JVM参数:
-Xmx20m -XX:+PrintGCDetails -verbose:gc -Xloggc:D:/tmp/gc.log -XX:+PrintGCDateStamps
日志分析:
JVM内存情况:
一些关键指标,例如吞吐量、GC暂停时间等
详细的GC统计
对象状态,包括创建的对象大小、对象从新生代晋升到老年代的大小等。
还有很多,自己去网站上看一下吧,不一一介绍了。
官方网站:https://gceasy.io/