JVM 调优经验总结

Posted 不能说的秘密go

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM 调优经验总结相关的知识,希望对你有一定的参考价值。

笔者之前整理了CPU load过高产生的原因及排查
这次针对java进程方面考虑一下JVM调优的原因

JVM 究竟需不需要调优?

JVM 经过这么多年的发展和验证,整体是非常健壮的。个人认为99%的情况下,基本用不到 JVM 调优。

通常来说,我们的 JVM 参数配置大多还是会遵循 JVM 官方的建议,例如:

  • -XX:NewRatio=2,年轻代:老年代=1:2
  • -XX:SurvivorRatio=8,eden:survivor=8:1
  • 堆内存设置为物理内存的3/4左右
  • 等等

JVM 参数的默认(推荐)值都是经过 JVM 团队的反复测试和前人的充分验证得出的比较合理的值,因此通常来说是比较靠谱和通用的,一般不会出大问题。

当然,更重要的是,大部分的应用 QPS 都不到10,数据量不到几万,这种低压环境下,想让 JVM 出问题,说实话也挺难的。
大部分情况遇到的应该是自己的代码 bug 导致 OOM、CPU load高、GC频繁啥的,这些场景也基本都是代码修复即可,通常不需要动 JVM。
当然具体也有些场景需要JVM 调优的,笔者整理几个平时工作遇到的。

JVM 优化步骤?

1.分析和定位当前系统的瓶颈

对于JVM的核心指标,我们的关注点和常用工具如下:

1)CPU指标

查看占用CPU最多的进程
查看占用CPU最多的线程
查看线程堆栈快照信息
分析代码执行热点
查看哪个代码占用CPU执行时间最长
查看每个方法占用CPU时间比例

涉及主要linux命令

// 显示系统各个进程的资源使用情况
top
//显示一个进程ID的线程运行信息列表 (按键P按CPU占有资源排序)
top -Hp pid
// 查看当前 Java 进程的线程堆栈信息
jstack pid

常见的工具:JProfiler、JVM Profiler、Arthas等。

2)JVM 内存指标

查看当前 JVM 堆内存参数配置是否合理
查看堆中对象的统计信息
查看堆存储快照,分析内存的占用情况
查看堆各区域的内存增长是否正常
查看是哪个区域导致的GC
查看GC后能否正常回收到内存

// 查看当前的 JVM 参数配置
ps -ef | grep java
// 查看 Java 进程的配置信息,包括系统属性和JVM命令行标志
jinfo pid
// 输出 Java 进程当前的 gc 情况
jstat -gc pid
// 输出 Java 堆详细信息
jmap -heap pid
// 显示堆中对象的统计信息
jmap -histo:live pid
// 生成 Java 堆存储快照dump文件
jmap -F -dump:format=b,file=dumpFile.phrof pid

常见的工具:Eclipse MAT、JConsole等。

3)JVM GC指标

首先,先要了解几个JVM的常用性能指标:

  • jvm.gc.time:每分钟的GC耗时在1s以内,500ms以内尤佳
  • jvm.gc.meantime:每次YGC耗时在100ms以内,50ms以内尤佳
  • jvm.fullgc.count:FGC最多几小时1次,1天不到1次尤佳
  • jvm.fullgc.time:每次FGC耗时在1s以内,500ms以内尤佳

通常来说,只要这几个指标正常,其他的一般不会有问题,如果其他地方出了问题,一般都会影响到这几个指标
查看每分钟GC时间是否正常
查看每分钟YGC次数是否正常
查看FGC次数是否正常
查看单次FGC时间是否正常
查看单次GC各阶段详细耗时,找到耗时严重的阶段
查看对象的动态晋升年龄是否正常

JVM 的 GC指标一般是从 GC 日志里面查看,默认的 GC 日志可能比较少,我们可以添加一些参数,来丰富我们的GC日志输出,方便我们定位问题。

// 打印GC的详细信息
-XX:+PrintGCDetails
// 打印GC的时间戳
-XX:+PrintGCDateStamps
// 在GC前后打印堆信息
-XX:+PrintHeapAtGC
// 打印Survivor区中各个年龄段的对象的分布信息
-XX:+PrintTenuringDistribution
// JVM启动时输出所有参数值,方便查看参数是否被覆盖
-XX:+PrintFlagsFinal
// 打印GC时应用程序的停止时间
-XX:+PrintGCApplicationStoppedTime
// 打印在GC期间处理引用对象的时间(仅在PrintGCDetails时启用)
-XX:+PrintReferenceGC

以上就是我们定位系统瓶颈的常用手段,大部分问题通过以上方式都能定位出问题原因,然后结合代码去找到问题根源。

针对定位出的系统瓶颈制定相应的优化方案,常见的有:

  • 代码bug:升级修复bug。典型的有:死循环、数据库加载数据过多、使用无界队列。
  • 不合理的JVM参数配置:优化 JVM 参数配置。典型的有:年轻代内存配置过小、堆内存配置过小、元空间配置过小。

笔者遇到的JVM问题汇总

1.metaspace导致频繁FGC问题

查看GC日志,发现出现FGC的原因是metaspace空间不够

Full GC (Metadata GC Threshold)
...
Metaspace       used 35337K, capacity 56242K, committed 56320K, reserved 1099776K

解释一下上述几个参数:

  • used :已使用的空间大小
  • capacity:当前已经分配且未释放的空间容量大小
  • committed:当前已经分配的空间大小
  • reserved:预留的空间大小

元空间主要适用于存放类的相关信息,而存在内存碎片化说明很可能创建了较多的类加载器(比如大量使用了反射,使用 BeanUtils.copyProperties ),同时使用率较低。

以上是关于JVM 调优经验总结的主要内容,如果未能解决你的问题,请参考以下文章

JVM 调优经验总结,你遇到过吗?

JVM调优经验分享

JVM调优经验分享

关于JVM内存垃圾回收性能调优总结篇

JVM 调优 1:“精通 JVM 调优,有过 JVM 调优经验”简历敢写吗?薪资涨 5k 的技巧

JVM调优经验参数设置