JVM调优

2023-12-31 08:00:04 浏览数 (1)

JVM调优

一.升级垃圾回收器

CMS(标记-清除)——》G1(标记整理)——》ZGC(染色指针,多重映射等技术)

二.指标

1.CPU指标

查看占用CPU最多的进程

查看占用CPU最多的线程

查看线程堆栈快照信息

分析代码执行热点

查看哪个代码CPU执行时间最长

查看每个方法占用CPU时间比例

代码语言:javascript复制
// 显示系统各个进程的资源使用情况
top
// 查看某个进程中的线程占用情况
top -Hp pid
// 查看当前 Java进程的线程堆栈信息
jstack pid
2.JVM内存指标
代码语言:javascript复制
//	查看当前的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
3.GC指标

​ (1)每分钟GC耗时(jvm.gc.time):每分钟GC耗时在1S以内,500ms以内为佳

​ (2)每次YGC耗时(jvm.gc.meantime):每次YGC耗时在100ms以内,50ms以内为佳

​ YGC:对新生代堆进行gc。

​ (3)FGC频率(jvm.fullgc.count):FGC最多几小时依次,一天不到一次为佳

​ FGC:全堆范围的gc。默认堆空间使用到达80%(可调整)

​ (4)每次FGC耗时(jvm.fullgc.time):每次FGC耗时在1s以内,500ms以内为佳

三,常见优化方案

1.升级修复bug,如死循环,使用无界队列

2.优化JVM参数配置,如年轻代内存配置过小,堆内存配置过小,元空间配置过小

四,两个案例

第一个案例:metaspace导致频繁FGC问题
1.看日志发现出现FGC的原因是metaspace空间不够
代码语言:javascript复制
Full GC (metadata GC Threshold)
2.进一步查看日志发现元空间存在内存碎片化现象

对应GC日志:

代码语言:javascript复制
Metaspace  use 35337K,capacity 56242K, committed 56320K, reserved 1099776K
3.通过dump堆存储文件发现存在大量DelegatingClassLoader

通过进一步分析,发现是由于反射导致大量DelegatingClassLoader。

在JVM上,最初是通过JNI调用来实现方法的反射调用,当JVM注意到通过反射经常访问某个方法时,它将生成字节码来执行相同的操作,称为膨胀(inflation)机制。如果使用字节码的方式,则会为该方法生成一个DelegatingClassLoader,如果存在大量方法经常反射调用,则会导致创建大量DelegatingClassLoader。

一般反射调用频次达到15次就会从JNI转字节码

4.优化策略

​ 1.适当调大 metaspace的空间带下

​ 2.优化不合理的反射调用。例如最常见的属性拷贝工具BeanUtils.copyProperties可以使用mapstruct替换

第二个案例:第二次调用SecureRandom随机数超时(这是我实际工作中遇到的问题)
1.问题出现在第一次跑一段代码很快,第二次跑就耗时一分多钟
2.定位问题,直接每句代码后跟个日志,定位了问题

​ SecureRamdom.getInstanceStrong()

这句代码执行时间超长

3.分析问题。

原因在于linux环境下,SecureRandom.getInstanceStrong()方法会从/dev/random,这是一种阻塞型读随机数,得获取到足够的系统扰动后才会生成随机数

4.问题解决

使用 new SecureRandom()来创建实例,这个是从/dev/urandom中读取随机数,是一种非阻塞型随机数

0 人点赞