JVM调优(十七)JVM常见调优问题和工具的使用
说辞
- 熟悉GC常见算法
- 熟悉常见的垃圾回收器,具有实际JVM调优经验
1 什么是调优
- 根据需求进行JVM优化和预调优
- 优化JVM的运行环境(慢、卡顿)
- 解决JVM运行过程中出现的各种问题(OOM)
2 JVM常用调优命令
-
jps
:JDK自带,全称java process,列出系统中运行的所有java进程 -
jinfo
:JDK自带,jinfo port,列出端口号对应jvm的详细信息,包括如- jvm版本
- 操作系统和编码信息
- 虚拟机参数(VM Flags):初始堆大小、最大堆大小以及设置的命令行参数等
-
jstat
:JDK自带,jstat -gc port
:打印jvm的内存使用情况jstat -gc port time
:实时监测JVM内存使用情况,每time ms打印一次
-
top
:Linux命令,打印出目前系统进程的资源使用情况,可以定位哪些进程在消耗资源,在实际开发过程中,一般会进行系统的监控,使用Zabbix+Promethems
来进行系统的监控报警top -Hp port
:打印端口号下的所有线程的资源使用情况- -d:指定top命令间隔几秒钟更新,默认为3秒
- -i:使top不显示任何闲置或者僵死进程
- -p:通过进程id仅仅监视某个进程
-
jstack
:JDK自带,追踪java线程的资源使用情况,包括线程的名字、线程的状态、线程调用的方法堆栈,jstack一般用于查找具体的哪些java线程在占用内存、cpu甚至出现死锁- 阿里编码规范中就规定每个线程都必须起一个有意义的名字,方便进行jstack回溯
-
jmap -histo pid
:主要用于查看pid的java进程对应的JVM中加载了哪些类,然后用这些类又创建了多少对象
1.1 jmap
jmap -histo port
:主要用于查看port端口下的java进程对应的JVM中加载了哪些类,然后用这些类又创建了多少对象jmap -dumy:format=b,file=2023.8.13.hprof pid
:将当前pid的java进程的JVM转储为一个文件,然后使用一些图形化工具对转储文件进行分析即可,也可以使用jhat命令
针对转储文件生成一个网页分析,常见的图形化分析工具有:- MAT
- MemoryInitializeTool
- Jprofile(收费)
- jvisualVM(JDK自带):使用流程在下面
3 调优工具
- Jconsole
- JvisualVM
- Jprofiler
- Java Flight Recorder
- GCViewer
- GC Easy
3.1 jvisualVM
转储文件分析
-
首先将jmap生成的转储文件装入jvisualVM,然后软件会分析出快照文件的一些基本信息和环境信息,以及转储文件上的线程信息
-
然后也会有加载到该快照JVM的类信息和对应该类创建的实例的数量
-
也可以通过一些OQL(Object Query Language)查询语句,查询JVM堆中包含某个类的所有对象信息以及产生该对象的方法信息
select * from java.lang.String
监控、线程和抽样器
-
可以远程监控进程CPU和堆的一个使用情况以及装入的进程和线程的总数
-
抽样器则可以针对CPU和内存进行抽样得到类名及其使用的资源情况
4 实际开发的JVM调优
其实上面面这些远程的图形化调优工具在生产过程中很少使用,因为
- 远程监控的话需要服务器开启端口号并设置防火墙
- 远程执行如jmap命令,会进行STW让堆暂停,然后导出堆快照文件再让jvm运行,肯定会对线上运行的进程造成冲击
1 怎么在不影响线上服务的情况下进行JVM问题排查调优呢?
解决方案主要有:
-
在启动JVM的时候设置参数
HeapDumpOnMemoryError
,可以在内存异常停顿的时候,自动转存堆的快照文件,方便在系统运行的时候进行日志的解析排查问题而不影响线上的环境:java -XX:PrintGCDetail -XX:HeapDumpOnMemoryError
-
对于高可用的服务集群,集群之间互为备份,则可以先停掉一个服务,然后使用
jmap
命令生成dump文件,然后再使用相关工具进行解析排查 -
在备用服务器上进行压测的时候进行
-
使用阿里的Arthas进行线上监控
-
在服务接收请求的时候,使用比如网易的TCPCopy将请求复制一份打到备用服务器,然后在备用服务器上进行相关的监控操作和问题排查
2 阿里Arthas
-
启动Arthas,一般使用shell脚本或者直接命令行的方式进行启动
java - jar arthas-boot.jar
-
启动之后Arthas就会监测到系统当前正在运行的Java进程,会携带一个内部编号
-
输入想要监控的进程的内部编号,Arthas即可挂到该进程上,对进程进行了一系列的监测和影响
-
Arthas常用命令:
-
dashboard
:图形化显示出所有进程的运行情况,包括哪些进程在占用CPU、内存的使用情况以及整个进程的参数情况 -
Thread
:列出当前进程运行的所有线程的状态和资源使用情况thread id
:列出指定线程id的线程的方法调用情况,类似于jstack
-
thread -b
:检查当前进程是否存在死锁 -
heap dumy
:等同于jmap,即对堆内存进行文件转储 -
jad 全类名
:打印出加载该类的类加载器、存在的系统位置以及对源代码进行反编译的结果源代码的反编译结果有什么用呢?
- 对于产生的动态代理的类,就可以使用反编译检查是否正确
- 使用反编译可以检查代码类的版本
-
redfine /xxxx.java
:可以在服务不重启的情况下,对运行的程序进行源代码替换太牛了
-
trace className classMethod
:单机情况下,追踪指定方法的调用的时间和其他方法的调用情况,一般用于全链路追踪&压测,如下A方法调用过程中,1000ms用于本方法执行,5004ms用于调用B方法
-
5 JVM堆设置参数
堆空间大小设置:
- -Xms 设置堆空间(新生代+老年代)的初始内存大小
- -X 是jvm的运行参数
- ms 是memory start的缩写
- -Xmx:设置堆空间(新生代+老年代)的最大内存大小
一般情况下JVM的初始堆大小和最大堆大小设置相同的值,原因是:
- 防止内存震荡和内存抖动
- 如果初始堆大小小于最大的大小,那么随着程序的运行堆会进行空间的拓展和收缩,JVM就会消耗时间去计算空间的拓展和收缩造成浪费
6 OOM定位排查总结
-
jps、top查看当前系统运行的java进程及其资源使用情况
-
jstat -gc port
:打印jvm的内存使用情况 -
jstack
:JDK自带,追踪java线程的资源使用情况,包括线程的名字、线程的状态、线程调用的方法堆栈,jstack一般用于查找具体的哪些java线程在占用内存、cpu甚至出现死锁 -
jmap -histo port
:主要用于查看port端口下的java进程对应的JVM中加载了哪些类,然后用这些类又创建了多少对象 -
先通过jmap生成jvm转储文件,然后使用一些图形化工具对转储文件进行分析
-
经过上面几种工具的使用,基本能够定位到导致出现OOM的地方了
7 CPU标高,如何定位?
-
首先通过系统的top命令、堆转储文件或者Arthas的实时监控查看是哪个线程在占用CPU
-
然后如果这个线程是业务线程,就说明业务代码有问题,比如导致出现死循环、CPU大量计算等情况,需要去使用比如
jstack
命令或者Arthas的thread命令
追踪java线程的资源使用情况,(jstack
命令包括线程的名字、线程的状态、线程调用的方法堆栈,jstack一般用于查找具体的哪些java线程在占用内存、cpu甚至出现死锁) -
而如果线程是GC线程,那就说明系统在频繁地
Full GC
回收,那么这时候就需要去查看GC日志,看看是否在频繁回收,查看回收情况,如果每次回收还是正常回收说明当前系统的请求压力很大不一定是系统存在问题,而如果每次都回收不掉只回收很少的空间,则说明出现内存泄露了 -
压力很大该怎么办。。
-
内存泄露该怎么办。。