Java学习篇之JVM 调优

Java学习篇之JVM 调优

  • [一、JVM 是什么?](#一、JVM 是什么?)
  • [二、JVM 官方参数建议](#二、JVM 官方参数建议)
  • 三、JVM调优的场景
  • 四、如何监控JVM
  • 五、JVM调优的流程步骤
    • [1. 明确优化目标](#1. 明确优化目标)
    • [2. 监控和分析](#2. 监控和分析)
    • [3. 确定调优参数](#3. 确定调优参数)
    • [4. 实施调优策略](#4. 实施调优策略)
    • [5. 持续观察和调整](#5. 持续观察和调整)
    • [6. 定期评估和优化](#6. 定期评估和优化)

一、JVM 是什么?

JVM,全称Java Virtual Machine(Java虚拟机),是一个能够运行Java字节码的抽象计算机。

JVM是Java跨平台特性的核心。Java源代码在编译成字节码后,可以在任何支持Java的平台上运行,只要该平台安装了相应的JVM。这是因为JVM将Java字节码转换成特定平台上的机器码来执行,从而实现了"一次编写,到处运行"的跨平台特性。

二、JVM 官方参数建议

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

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

1. 堆内存设置

参数 描述 官方建议/说明
-Xms 设置JVM的初始堆大小 可以设置为物理内存的1/64(但小于1GB);对于高并发应用,建议与-Xmx相同
-Xmx 设置JVM的最大堆大小 可以设置为物理内存的1/4(但小于1GB)
-Xmn 设置年轻代的初始和最大大小 可以配置为整个堆的3/8;或使用-XX:NewSize/-XX:MaxNewSize分别设置

2. 年轻代与老年代比例

参数 描述 官方建议/说明
-XX:NewRatio 设置年轻代与老年代的比例 默认值为2(即老年代是年轻代的2倍)
-XX:SurvivorRatio 设置Eden区与一个Survivor区的大小比例 默认值为8,表示Eden区与Survivor区的比例为8:1

3. 线程堆栈设置

参数 描述 官方建议/说明
-Xss 设置每个线程的堆栈大小 JDK5.0后默认1MB;小型应用可能128KB足够,大型应用建议256KB

4. 非堆内存设置

参数 描述 官方建议/说明
-XX:PermSize 设置持久代的初始大小(JDK8已弃用) JDK8前用于控制方法区内存大小
-XX:MaxPermSize 设置持久代的最大大小(JDK8已弃用) JDK8前用于控制方法区内存大小
-XX:MetaspaceSize 设置元空间的初始大小(JDK8及以后) 替代了PermSize,用于存放类的元数据
-XX:MaxMetaspaceSize 设置元空间的最大大小(JDK8及以后) 替代了MaxPermSize

5. 垃圾收集器设置

参数 描述 官方建议/说明
-XX:+UseSerialGC 使用串行垃圾收集器 默认GC方式,适用于小型应用和单处理器环境
-XX:+UseParNewGC 在年轻代中使用并行线程进行垃圾收集 可以与CMS GC一起使用
-XX:+UseParallelGC 在年轻代中使用并行垃圾收集器 适用于多处理器系统
-XX:+UseParallelOldGC 在老年代中使用并行垃圾收集器 与-XX:+UseParallelGC一起使用
-XX:+UseConcMarkSweepGC 使用CMS垃圾收集器 在GC运行时对应用程序影响较小

6. 辅助信息设置

参数 描述 官方建议/说明
-XX:+PrintGCDetails 打印垃圾收集的详细情况 用于调试和性能分析
-Xloggc:filename 将GC日志信息记录到指定文件 便于分析和监控JVM的垃圾回收行为

7. 其他重要参数

参数 描述 官方建议/说明
-XX:MinHeapFreeRatio 设置GC事件后允许的最小可用堆空间百分比 控制JVM何时扩展堆大小
-XX:MaxHeapFreeRatio 设置GC事件后允许的最大可用堆空间百分比 控制JVM何时收缩堆大小
-XX:MaxDirectMemorySize 设置Direct ByteBuffer分配的堆外内存的最大大小 当达到此大小时,将触发Full GC

请注意,这些建议是基于Oracle JDK的通用指南,并且可能会随着JVM版本的更新而有所变化。

在实际应用中,可能还需要根据具体的应用场景、硬件环境和性能需求进行进一步的调整和优化。

同时,也需要注意参数的兼容性和稳定性问题。

三、JVM调优的场景

主要就是出现以下情况时,就需要注意对JVM进行调优了

  1. 当应用程序运行缓慢或出现卡顿,或是偶尔响应慢
  2. 应用程序频繁出现内存溢出(OutOfMemoryError)或内存泄漏等问题,

四、如何监控JVM

JVM监控工具分为JDK自带工具和第三方工具两大类。

  • JDK自带工具(常用的):jconsole、visualvm
  • 第三方工具(常用的):JProfiler、YourKit

JDK自带工具常用命令:

  • jstack pid: 打印堆栈相关执行信息,可以用于死锁发现。
  • jinfo pid: 打印进程的启动详细参数、JVM正在使用的参数。
  • jstat -gc pid: 打印各个分代的内存使用情况。可以每个一段时间打印一次。
  • jvisualvm: windows图形化界面 ,不常用。上线之前内测可以使用
  • jmap: 如果内存特别大,jmap会导致线程的停止,所以线上不能使用
    线上时不能dump下来文件,因为文件可能很大(堆内存占了多少文件就有多大),dump时java程序会暂停,线上不能dump。
    jmap -histo pid | head -n 20 :查找有多少对象产生,及对象占用的内存,对象的名称。可用于内存泄露导致的OOM。

五、JVM调优的流程步骤

JVM调优流程步骤可以归纳为以下几点:

1. 明确优化目标

在开始调优之前,首先需要明确优化的目标。这包括响应时间、吞吐量、内存使用率等指标。明确目标后,可以更有针对性地进行调优。

2. 监控和分析

  1. 使用监控工具:利用Java VisualVM、JConsole、JProfiler等监控工具,分析CPU使用率、内存使用情况和垃圾回收频率等指标。

JDK自带工具常用命令:

  • jstack pid: 打印堆栈相关执行信息,可以用于死锁发现。
  • jinfo pid: 打印进程的启动详细参数、JVM正在使用的参数。
  • jstat -gc pid: 打印各个分代的内存使用情况。可以每个一段时间打印一次。
  • jvisualvm: windows图形化界面 ,不常用。上线之前内测可以使用
  • jmap: 如果内存特别大,jmap会导致线程的停止,所以线上不能使用
    线上时不能dump下来文件,因为文件可能很大(堆内存占了多少文件就有多大),dump时java程序会暂停,线上不能dump。
    jmap -histo pid | head -n 20 :查找有多少对象产生,及对象占用的内存,对象的名称。可用于内存泄露导致的OOM。
  1. 分析GC日志:通过GC日志,了解垃圾回收的频率、停顿时间以及内存使用情况,帮助定位性能瓶颈。

例如:

bash 复制代码
-Xloggc:/path/to/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps

这些选项将GC日志记录到指定的文件(/path/to/gc.log),并打印详细的GC信息和时间戳。

然后,我们可以分析GC日志以了解垃圾回收的频率、停顿时间和内存使用情况。例如,我们可以查>找Full GC的发生频率和每次Full GC的停顿时间。

3. 确定调优参数

根据监控和分析的结果,确定需要调整的JVM参数。常见的JVM参数包括:

  1. 堆内存设置:通过-Xms和-Xmx设置初始和最大堆内存大小。

例如:

bash 复制代码
-Xms512m -Xmx512m

这将初始堆内存设置为512m,最大堆内存设置为512m。两者最好一致

  1. 垃圾收集器选择:选择合适的垃圾收集器,如G1、CMS等,以优化内存管理。

例如:

选择G1垃圾收集器:以优化内存管理和减少停顿时间。

bash 复制代码
-XX:+UseG1GC

调整G1垃圾收集器的参数:以进一步优化性能。

bash 复制代码
-XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=35

这将G1垃圾收集器的目标停顿时间设置为200毫秒,并将触发并发GC的堆占用百分比设置为35%。

  1. 线程栈大小:通过-Xss设置每个线程的堆栈大小,以减少线程上下文切换的开销。

4. 实施调优策略

  1. 调整JVM参数:根据确定的调优参数,调整JVM的启动参数。

例如:如果我们在Linux系统上使用java命令启动应用程序,我们可以这样设置:

bash 复制代码
java -Xms512m -Xmx512m -Xloggc:/path/to/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=35 -jar myapp.jar
  1. 优化代码:减少不必要的对象创建、使用高效的数据结构、避免过度的同步等,都可以显著提升应用的性能。

5. 持续观察和调整

  1. 持续监控:在调整参数和优化代码后,使用监控工具持续观察应用的性能变化。
  2. 对比性能指标:通过对比调优前后的性能指标,确认是否达到了预期的优化目标。
  3. 重新评估和调整:如果没有达到目标,可能需要重新评估调优策略,进行进一步的调整。

6. 定期评估和优化

性能调优是一个持续的过程。随着应用的演变和用户负载的变化,可能需要定期重新评估和调整JVM参数。定期的性能测试和监控可以帮助及时发现潜在问题,确保系统的稳定性和高效性。

参考文章

【1】面试官:如何进行 JVM 调优(附真实案例)

【2】【JVM】JVM 实战调优指南赋案例(保姆篇)

【3】JVM调优实例记录

【4】【Java】JVM调优操作手册(实战篇)

【5】JVM性能优化实战手册:从监控到调优策略

相关推荐
xmh-sxh-13144 分钟前
jdk各个版本介绍
java
天天扭码23 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶24 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺28 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序35 分钟前
vue3 封装request请求
java·前端·typescript·vue
陈王卜1 小时前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、1 小时前
Spring Boot 注解
java·spring boot
java亮小白19971 小时前
Spring循环依赖如何解决的?
java·后端·spring
飞滕人生TYF1 小时前
java Queue 详解
java·队列
武子康1 小时前
大数据-230 离线数仓 - ODS层的构建 Hive处理 UDF 与 SerDe 处理 与 当前总结
java·大数据·数据仓库·hive·hadoop·sql·hdfs