JVM调优
1、有哪些常用的命令行性能监控和故障处理工具?
操作系统工具
- top:显示系统整体资源使用情况
- vmstat:监控内存和CPU
- iostat:监控IO使用
- netstat:监控网络使用
JDK性能监控工具
- jps:虚拟机进程查看
- jstat:虚拟机运行时信息查看
- jinfo:虚拟机配置查看
- jmap:内存映像(导出)
- jhat:堆转储快照分析
- jstack:Java堆栈跟踪
- jcmd:实现上面除了jstat外所有命令的功能
2、了解哪些可视化的性能监控和故障处理工具?
以下是一些JDK自带的可视化性能监控和故障处理工具:
- JConsole
- VisualVM
- Java Mission Control
JMC主要界面
除此之外,还有一些第三方的工具:
- MAT
Java 堆内存分析工具。
- GChisto
GC 日志分析工具。
- GCViewer
GC 日志分析工具。
- JProfiler
商用的性能分析利器。
- arthas
阿里开源诊断工具。
- async-profiler
Java 应用性能分析工具,开源、火焰图、跨平台。
3、讲一下常见的JVM参数?
堆配置:
- -Xmx3550: 设置堆最大值
- -Xms3660m: 设置初始堆大小
- -Xss128k: 设置线程栈大小
- -Xmn2g: 设置年轻代大小
- -XX:NewSize=1024m: 设置年轻代初始值
- -XX:MaxNewSize=1024m: 设置年轻代最大值
- -XX:SurvivorRatio=4: 设置Survivor区与Eden区比值
- -XX:MaxTenuringThreshold=15: 设置分代年龄阈值,满15就进入老年代。
- -XX:PretenureSizeThreshold: 大对象直接进入老年代
收集器设置:
- -XX:+UseSerialGC:设置串行收集器
- -XX:+UseParallelGC:设置并行收集器
- -XX:+UseParalledlOldGC:设置并行年老代收集器
- -XX:+UseConcMarkSweepGC:设置并发收集器
打印GC回收的过程日志信息
- -XX:+PrintGC
- -XX:+PrintGCDetails
- -XX:+PrintGCTimeStamps
- -Xloggc:filename
4、有做过JVM调优吗?
实际上,JVM调优是不得已而为之,代码重构比JVM调优会更好,调优流程图大致如下:
真实案例:
电商公司的运营后台系统,偶发性的引发OOM异常,堆内存溢出。
- 因为是偶发性的,所以第一次简单的认为就是堆内存不足导致,单方面的加大了堆内存从4G调整到8G -Xms8g。
- 但是问题依然没有解决,只能从堆内存信息下手,通过开启了-XX:+HeapDumpOnOutOfMemoryError参数 获得堆内存的dump文件。
- 用JProfiler 对 堆dump文件进行分析,通过JProfiler查看到占用内存最大的对象是String对象,本来想跟踪着String对象找到其引用的地方,但dump文件太大,跟踪进去的时候总是卡死,而String对象占用比较多也比较正常,最开始也没有认定就是这里的问题,于是就从线程信息里面找突破点。
- 对线程进行分析,先找到了几个正在运行的业务线程,然后逐一跟进业务线程看了下代码,有个方法引起了我的注意: 导出订单信息。
- 因为订单信息导出这个方法可能会有几万的数据量,首先要从数据库里面查询出来订单信息,然后把订单信息生成excel,这个过程会产生大量的String对象。
- 为了验证自己的猜想,于是准备登录后台去测试下,结果在测试的过程中发现导出订单的按钮前端居然没有做点击后按钮置灰交互事件,后端也没有做防止重复提交,因为导出订单数据本来就非常慢,使用的人员可能发现点击后很久后页面都没反应,然后就一直点,结果就大量的请求进入到后台,堆内存产生了大量的订单对象和EXCEL对象,而且方法执行非常慢,导致这一段时间内这些对象都无法被回收,所以最终导致内存溢出。
- 知道了问题就容易解决了,最终没有调整任何JVM参数,只是做了两个处理:
- 在前端的导出订单按钮上加上了置灰状态,等后端响应之后按钮才可以进行点击
- 后端代码加分布式锁,做防重处理;
5、线上服务CPU占用过高怎么排查?
- 首先需要找出哪个进程占用CPU高
- top: 列出系统各个进程的资源占用情况;
- 然后找到对应进程里哪个线程占用CPU高
- top -Hp 进程ID: 列出对应进程里面的线程占用资源情况
- 找到对应线程ID后,再打印出对应线程的堆栈信息
- printf "%x\n" PID: 把线程ID转换为16进制。
- jstack PID: 打印出进程的所有线程信息,从打印出来的线程信息中找到上一步转换为16进制的线程ID对应的线程信息。
- 最后根据线程的堆栈信息定位到具体业务方法,从代码逻辑中找到问题所在。
6、内存持续上升,我该如何处理?【⭐】
分析:内存飚高如果是发生在java进程上,一般是因为创建了大量对象所导致,持续飚高说明垃圾回收跟不上对象创建的速度,或者内存泄露导致对象无法回收。
处理过程如下:
- 先观察垃圾回收的情况
- jstat -gc PID 1000: 查看GC次数,时间等信息,每隔一秒打印一次。
- jmap -histo PID | head -20: 查看堆内存占用空间最大的前20个对象类型,可初步查看是哪个对象占用了内存。
- 分析:如果每次GC次数频繁,而且每次回收的内存空间也正常,那说明是因为对象创建速度快导致内存一直占用很高;如果每次回收的内存非常少,那么很可能是因为内存泄露导致内存一直无法被回收。
- 导出堆内存文件快照
jmap -dump:live,format=b
,file=/home/myheapdump.hprof PID dump
堆内存信息到文件。
- 使用visualVM对dump文件进行离线分析,找到占用内存高的对象,再找到创建该对象的业务代码位置,从代码和业务场景中定位具体问题。
7、说一下JVM调优的命令?
- jps:查看当前系统有哪些Java进程。
- jmap:查看堆内存占用情况,只能查看某一时刻的堆内存占用情况。
- 使用方式: jamp -heap 进程id;
- 举例:jmap -heap 7988 (查看当前7988进程的堆内存占用情况)。
- jstack:jstack用于生成java虚拟机当前时刻的线程快照,用来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
8、频繁 minor gc 和频繁Full GC怎么办?
频繁 minor gc
- 通常情况下,由于新生代空间较小,Eden区很快被填满,就会导致频繁Minor GC,因此可以通过增大新生代空间-Xmn来降低Minor GC的频率。
频繁 Full GC
有哪些原因导致FGC?
- 大对象:系统一次性加载了过多数据到内存中,导致大对象进入了老年代;
- 内存泄漏:频繁创建了大量对象,但是无法被回收;
- 程序频繁生成一些长生命周期的对象,当这些对象的存活年龄超过分代年龄时便会进入老年代,最后引发FGC;
- 代码中显式调用了gc方法,包括自己的代码甚至框架中的代码。
- JVM参数设置问题:包括总内存大小、新生代和老年代的大小、Eden区和S区的大小、元空间大小、垃圾回收算法等等。
排查问题时可以使用的工具:
- 公司的监控系统;
- JDK的自带工具,包括jmap、jstat等常用命令;
- 可视化的堆内存分析工具:JVisualVM、MAT等。
如何排查?
- 查看监控,了解出现问题的时间点以及当前FGC的频率;
- 了解JVM的参数设置,包括:堆空间各个区域的大小设置,新生代和老年代分别采用了哪些垃圾收集器,然后分析JVM参数设置是否合理。
- 针对大对象或者长生命周期对象导致的FGC,可通过 jmap -histo 命令并结合dump堆内存文件作进一步分析,需要先定位到可疑对象。
- 通过可疑对象定位到具体代码再次分析,这时候要结合GC原理和JVM参数设置,弄清楚可疑对象是否满足了进入到老年代的条件才能下结论。
9、有没有处理过内存泄漏问题?是如何定位的?
内存泄漏是内在病源,外在病症表现可能有:
- 应用程序长时间连续运行时性能严重下降
- CPU 使用率飙升,甚至到 100%
- 频繁 Full GC,各种报警,例如接口超时报警等
- 应用程序抛出 OutOfMemoryError 错误
- 应用程序偶尔会耗尽连接对象
主要有以下排查操作步骤:
- 使用
jps
查看运行的 Java 进程 ID; - 使用
top -p [pid]
查看进程使用 CPU 和 内存 的情况; - 使用
top -Hp [pid]
查看进程下的所有线程占 CPU 和内存 的情况 - 线程 ID 转换为 16 进制:
printf "%x\n" [pid]
,输出的值就是线程栈信息中的 nid。 - 抓取线程栈:
jstack 29452 > 29452.txt
,可以多抓几次做个对比。 - 使用
jstat -gcutil [pid] 5000 10
每隔 5 秒输出 GC 信息,输出 10 次,查看 YGC 和 Full GC 次数。通常会出现 YGC 不增加或增加缓慢,而 Full GC 增加很快。 - 如果发现 Full GC 次数太多,就很大概率存在内存泄漏了
- 使用
jmap -histo:live [pid]
输出每个类的对象数量,内存大小(字节单位)及全限定类名。 - 生成 dump 文件,借助工具分析哪个对象非常多,基本就能定位到问题在哪了。