JVM学习.05 JVM常见的排障和调优

简介: 前面介绍了JVM相关的内存和线程相关的技术。对于JVM也算有了一个比较系统、完整的理论基础。理论总是作为指导实践的工具,但是从理论到实践,总会遇到一些虚拟机相关问题,故障。所以还需要学习一些常用的JVM排障工具,和一些常见的调优手段。

1、前言

前面介绍了JVM相关的内存和线程相关的技术。对于JVM也算有了一个比较系统、完整的理论基础。理论总是作为指导实践的工具,但是从理论到实践,总会遇到一些虚拟机相关问题,故障。所以还需要学习一些常用的JVM排障工具,和一些常见的调优手段。

2、故障排查常用工具

2.1、命令行工具

2.1.1、jps

JVM Process Status Tool(jps)虚拟机进程状态工具。顾名思义主要用来查看虚拟机进程,并显示虚拟机执行主类名称和这些进程的状态等。同Linux的PS指令类似。

jps命令格式为:

jps [option] [hostid]

示例:

image.png

参数:

选项

作用

-q

只输出LVMID(进程的本地虚拟机唯一ID),省略主类名称

-m

输出虚拟机进程启动时传递给main()的参数

-l

输出主类的全限定名,如果进程执行的式jar包,则输出jar的路径

-v

输出虚拟机进程启动的JVM参数

2.1.2、jstat

JVM Statistics Monitoring Tool(jstat),虚拟机统计信息监控工具。用于监视虚拟机各种运行状态信息。可以显示虚拟机进程的类加载、内存、垃圾收集、即时编译等运行时数据。

jstat命令格式为:

jstat [option vmid [interval [s|ms] [count] ] ]

示例:

image.png

S0,S1:代表Survivor0、Survivor1区

E:表示Eden区

O:表示老年代

M:表示永久代(元空间)

CCS:表示压缩类空间

YGC:表示Young GC

YGCT:表示Young GC Time,耗时

FGC:表示Full GC

FGCT:表示Full GC Time,耗时

CGC:表示并发GC次数

CGCT:表示并发GC耗时

GCT:表示GCV Time,GC总耗时

/**  * -gcutil 查看gc情况  * 7864 为进程pid  * 500 每间隔500ms执行一次  * 10 总共执行10次  * 所以下面的命令为:每间隔500ms,查询一次进程id为7864的gc情况,一共查询10次  */ jstat -gcutil 7864 500 10

参数(参数选项比较多,列举一些常用的,其他的自行查找):

选项

作用

-class

监视类加载信息、卸载数量、总空间以及类加载的耗时

-gc

监视Java堆情况

-gccause

功能同-gcutil,但是会额外输出导致上一次gc产生的原因

-gcutil

功能同-gc相同,但输出主要关注的已使用空间占总空间的百分比

-compiler

输出即使编译过的方法,耗时等

2.1.3、jmap

Memory Map for Java(jmap),用于生成JVM某一时刻运行的堆快照,即heapdump或dump文件。除了转储外,还可以查看当前的堆和方法区的详细信息等。

除了使用jmap,可以指定-XX:+HeapDumpOnOutOfMemoryError参数,可以让虚拟机出现内存溢出后自动生成dump文件。

注意:请尽可能不要在生产环境中使用jmap -dump来转储整个内存的dump文件。因为在dump过程中,会暂停所有执行线程的业务逻辑。会直接暂停线上业务的响应。

jmap命令格式为:

jmap [option ] vmid

示例:

image.png

参数:

选项

作用

-dump

生成Java堆快照。格式为:

jmap -dump:format=b,file=F://heap001.hprof {PID}

jmap -dump:live,format=b,file=F://heap001.hprof {PID} // live说明只dump出存活的对象

-heap

监视Java堆情况。只在Linux平台下有效

-histo

显示队中对象统计信息,包括类,实力数量,合计容量

-gcutil

功能同-gc相同,但输出主要关注的已使用空间占总空间的百分比

-F

当虚拟机进程堆-dump选项无响应时,可使用这个选项强制生成dump快照。只在Linux平台下有效

2.1.4、jhat

JVM Heap Analysis Tool(jhat),虚拟机堆快照分析工具。一般与jmap搭配使用。用来分析jmap生成的对快照。内置了一个微型的http/web服务器,分析结果可以通过浏览器访问既定的端口进行查看。但是个人建议可以使用第三方工具进行分析,如常用的MAT,jProfile等。

jhat命令格式为:

jhat -port 8080 d://xxx.hprof

接着访问http://localhost:8080即可。如果不指定-port 默认为7000。

示例:

image.png


image.png

image.png

2.1.5、jstack

Stack Trace for Java(jstack),堆栈跟踪工具。用于生成JVM当前时刻的线程快照,一般为threaddump或javacore文件。线程快照就是当前JVM内每一条线程正在执行的方法堆栈的集合,一般生成快照用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致长时间挂起等原因。

jstack命令格式为:

jstack [option] vmid

示例:

image.png

参数:

选项

作用

-F

当正常输出的请求不被响应时,强制输出线程堆栈

-l

出堆栈外,显示关于锁的附加信息

-m

如果调用到本地方法的话,可以显示c/c++的堆栈

2.2、可视化工具

2.2.1、jConsole

Java Monitoring and Management Console(jConsole),Java监视与管理控制台。是一个基于JMX的可视化监控,管理工具。其中一项我常用的功能是通过JMX的MBean堆系统进行信息收集和参数动态调整。如一次线上的最大可用线程过载,就是通过MBean中临时调整参数恢复业务的。

image.png

image.png

image.png

2.2.2、jvisualvm

All-in-One Java Troubleshooting Tool(VisualVM),我认为是JDK自带的监控和故障处理能力最强大的程序之一。也是我们平时使用最经常的JVM排障工具。

它不仅包含了常规的运行监控,故障处理外,还提供了比如性能分析等额外功能。

另外jvisualvm还支持安装插件,可以通过插件平台扩展该工具的功能。

jvisualvm除了可以监视本地进程外,还可以通过JMX远程连接。java启动程序的时候,可以通过启动参数配置JMX相关信息即可。

image.png

image.png

image.png

在工具菜单栏选择插件,可以自由安装想要的插件:

image.png

2.3、第三方工具

2.3.1、jProfile

JProfiler是一个商业授权的Java剖析工具,由EJ技术有限公司,针对的Java EE和Java SE应用程序开发的。

它把CPU、执行绪和内存的剖析组合在一个强大的应用中。JProfiler可提供许多IDE整合和应用服务器整合用途。

JProfiler的是一个独立的应用程序,但其提供Eclipse和IntelliJ等IDE的插件。

它允许两个内存剖面评估内存使用情况和动态分配泄漏和CPU剖析,以评估线程冲突。

----来自百度百科

image.png

2.3.2、MAT

Eclipse Memory Analyzer (MAT)是一个快速且功能丰富的Java堆分析器,可帮助您发现内存泄漏并减少内存消耗。

----来自百度百科

image.png

2.3.3、arthas

arthas,阿里开源的Java实时性能监控和问题排查工具。强烈推荐。具体使用方式可以参照我另一篇博客《java线上项目排查,Arthas简单上手》

3、常用的调优策略

3.1、 编码阶段的预防

良好的编码习惯可以减少一些常见的问题,也能使程序的性能提高。以下例举常见的几个编码阶段问题:

3.1.1、避免短命大对象

如byte[]。JVM中,大对象需要大量连续的内存空间,如很长的字符串或者元素数量很庞大的数组。jvm在分配空间时,有时候需要提前进行GC,以获取足够的空间分配。可以通过-XX:PretenureSizeThreshold指定大于该值的对象直接分配在老年代。

3.1.2、变量作用域

尽可能控制变量的作用域范围,尽可能不要定义全局变量。

3.1.3、String操作

String操作,尽可能使用Stringbuffer或者Stringbuilder,尽量减少字符串的+拼接。

3.1.4、锁操作

注意锁的粒度和范围。尽可能精确缩小锁的粒度。能不用锁就不用锁,能锁区块就不要锁整个方法体,能用对象锁,就不要用类锁。

3.2、部署阶段的预防

3.2.1、选用合适的硬件和软件设施

很多性能问题,大部分可以通过氪金的方式解决。如果通过氪金的方式解决,效率是最高的(当然要看实际情况)。这里指的选用合适版本并不是氪金,选用配置越高越好,主要指的是做好程序的规划,业务体量,以及良好的程序设计和部署用例。做好CPU密集型和IO密集型的业务处理,如果IO密集型的,就选用IOPS高的磁盘等等。

3.2.2、压力测试

程序编码完成后,做一些压力测试。一个好的程序不仅要满足功能需求,更需要满足非功能性需求。压力测试正式验证这些非功能性需求是否负责指标的一个有力手段。宁愿问题在测试阶段发生,也尽量避免在生产阶段发生。

3.3、常用的JVM参数配置

-Xms512M 设置Heap 空间最小值

-Xmx512M 设置Heap 空间最大值

-Xmn200M 设置Young区大小

-Xss 256K 设置线程栈大小

-XX:MaxGCPauseMillis=500 垃圾回收器最大的停顿时间

-XX:+UseG1GC 指定G1垃圾回收器(具体使用哪个垃圾回收期可以视程序要求而定)

-XX:NewRatio 新老生代的比值

-XX:+HeapDumpOnOutOfMemoryError  启动堆内存溢出打印

-XX:HeapDumpPath=heap.hprof 指定Heap快照打印位置

-XX:MinHeapFreeRatio   jvm heap 在使用率小于n时,heap进行收缩

-XX:MaxHeapFreeRatio   jvm heap 在使用率大于n时,heap进行扩张

3.4、问题排查和分析

3.4.1、CPU过载

CPU过高,可以通过top命令排查各个进程的资源占用情况。结合-Hp参数找到CPU过多的线程。

如果一台服务器部署应用过多,出现CPU争用情况,可以自主分配具体CPU核心,错开CPU核心使用。具体参照我另一篇博客《windows系统启动java程序限制cpu核心数》

3.4.2、线程死锁

可以使用jstack或者jvisualvm或arthas分析当前锁的情况进行排查。

3.4.3、OOM

出现OOM,先要观察报错类型。

  • java.lang.OutOfMemoryError: java heap space
  • heap溢出.检查是否存在内存泄漏问题. 分析堆栈对象情况
  • java.lang.OutOfMemoryError: Meta space
  • 可通过JVM类加载的情况进行排查.jstat或者实时监测工具排查..
  • java.lang.OutOfMemoryError:GC over head limit exceeded
  • 系统处于高频的GC状态,而且回收的效果依然不佳的情况分析GC日志曲线集合堆栈分析排查.

关于OOM问题,个人经验在启动参数中加入-XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=heap.hprof 指定溢出时候的dump文件生成目录,一旦生产出现OOM问题,需要紧急恢复情况下,大多数会采用重启的方案(前提是单机应用,且业务需要紧急恢复的情况,而且重启能解决99%的问题,如果不行,那就重启2次)。一旦重启后,内存镜像丢失就不利于接下来的问题分析和定位。所以配置完参数后,出现oom问题,系统自动帮我们dump当下的内存文件,我们就可以放心大胆重启了。然后再逐步分析hprof文件。

......

应该还有很多,这就不一一例举了,目前仅能想到这么多。

4、小结

前面几篇分别介绍了JVM的一些结构体系。对于Java程序员来说,不管是项目中,还是面试,经常会遇到关于JVM相关的问题。同时通过对JVM的深入学习,能够更加从容应对JVM底层相关的一些问题以及解决措施。

相关文章
|
25天前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
50 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
25天前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
25 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
7天前
|
存储 监控 Java
JVM进阶调优系列(8)如何手把手,逐行教她看懂GC日志?| IT男的专属浪漫
本文介绍了如何通过JVM参数打印GC日志,并通过示例代码展示了频繁YGC和FGC的场景。文章首先讲解了常见的GC日志参数,如`-XX:+PrintGCDetails`、`-XX:+PrintGCDateStamps`等,然后通过具体的JVM参数和代码示例,模拟了不同内存分配情况下的GC行为。最后,详细解析了GC日志的内容,帮助读者理解GC的执行过程和GC处理机制。
|
15天前
|
Arthas 监控 数据可视化
JVM进阶调优系列(7)JVM调优监控必备命令、工具集合|实用干货
本文介绍了JVM调优监控命令及其应用,包括JDK自带工具如jps、jinfo、jstat、jstack、jmap、jhat等,以及第三方工具如Arthas、GCeasy、MAT、GCViewer等。通过这些工具,可以有效监控和优化JVM性能,解决内存泄漏、线程死锁等问题,提高系统稳定性。文章还提供了详细的命令示例和应用场景,帮助读者更好地理解和使用这些工具。
|
21天前
|
监控 架构师 Java
JVM进阶调优系列(6)一文详解JVM参数与大厂实战调优模板推荐
本文详述了JVM参数的分类及使用方法,包括标准参数、非标准参数和不稳定参数的定义及其应用场景。特别介绍了JVM调优中的关键参数,如堆内存、垃圾回收器和GC日志等配置,并提供了大厂生产环境中常用的调优模板,帮助开发者优化Java应用程序的性能。
|
25天前
|
Java 应用服务中间件 程序员
JVM知识体系学习八:OOM的案例(承接上篇博文,可以作为面试中的案例)
这篇文章通过多个案例深入探讨了Java虚拟机(JVM)中的内存溢出问题,涵盖了堆内存、方法区、直接内存和栈内存溢出的原因、诊断方法和解决方案,并讨论了不同JDK版本垃圾回收器的变化。
25 4
|
25天前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
38 3
|
26天前
|
SQL 缓存 Java
JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
这篇文章详细介绍了JVM中类文件的初始化过程、硬件层面的数据一致性问题、缓存行和伪共享、指令乱序执行问题,以及如何通过`volatile`关键字和`synchronized`关键字来保证数据的有序性和可见性。
24 3
|
26天前
|
缓存 前端开发 Java
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
34 3
|
26天前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
47 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配