JVM调优实战

1.背景

Java虚拟机(JVM)在Java技术体系中占据着核心地位。JVM调优能够显著提升应用的响应速度、吞吐量以及资源利用效率,从而保障系统的稳定高效运行。本章为JVM调优前置知识,主要介绍:什么时候需要调优?JVM如何监控和诊断性能、如何设置参数、常用的JVM参数等。

2.调优时机

在进行JVM调优时,需要综合考虑JVM的内存管理、垃圾回收、线程管理等方面,通过合理的配置和参数调整,实现最佳的性能和资源利用效果。
通常出现以下情况就需要JVM调优:

  • 性能问题:例如应用程序的响应时间过长、吞吐量低、频繁发生垃圾回收等情况,可能需要进行JVM调优。
  • 内存问题:当应用程序经常发生内存溢出错误或持续占用过多的内存时,表明堆内存配置不合理或垃圾回收策略需要调整。
  • 并发问题:在高并发环境下,如果应用程序出现线程竞争、死锁或阻塞等问题,可以考虑通过调整线程池大小、线程栈大小等参数来改善并发性能。

3.JVM调优监控和诊断

那么,当生产遇到上述类似的情况时,我们如何发现问题?一般会通过系统监控来诊断问题。通常诊断的工具有两类:一种是jdk自带命令行工具;一种是借助第三方性能分析工具。

3.1 基础配置

主机参数:4核8G
Oracle jdk版本:1.8.0_221
Java自带很多命令行工具,获取命令具体参数选项,可以通过 -help 获取。

3.2 常用的命令行工具介绍。
3.2.1 jps:查看正在运行的Java进程

通过jps命令获取Java进程的进程ID(PID)以及主类名称或JAR文件的完整路径名。
参数选项:

  • -l:输出主类或者JAR的完全路径名。例如,运行jps -l命令将列出所有 - Java进程及其对应的主类名称或JAR文件的完整路径名。
  • -v:输出JVM参数。列出每个Java进程的JVM参数信息。
  • -m:输出JVM启动时传递给main()方法的参数。
  • -V:(特定环境或版本可能支持)提供特定于该环境或版本的输出或功能。
  • <hostid>:指定要查询 Java 进程信息的远程主机。
3.2.2 jstat:查看JVM统计信息

jstat 是 Java 虚拟机(JVM)自带的监控工具,用于查看 HotSpot JVM 的性能统计信息。
jstat - [-t] [-h] [ []]
基础参数:

  • -t:展示从虚拟机运行到现在的性能数据
  • -h:每隔lines行展示行头部信息
  • <vmid>:JVM进程的虚拟机标识符。
  • <interval>:两次统计信息收集之间的时间间隔(秒)。
  • <count>:收集统计信息的次数。

性能参数:

  • -class:显示类加载器的统计信息。
  • -compiler:显示即时编译器的统计信息。
  • -gc:显示垃圾收集的统计信息。
  • -gccapacity:显示各内存池的容量和使用情况。
  • -gccause:显示上一次或当前垃圾收集的原因及相关统计信息。
  • -gcnew:显示新生代的垃圾收集统计信息。
  • -gcnewcapacity:显示新生代内存池的容量和使用情况。
  • -gcold:显示老年代的垃圾收集统计信息。
  • -gcoldcapacity:显示老年代内存池的容量和使用情况。
  • -gcpermcapacity:显示永久代的容量和使用情况(Java 8 及以后版本可能不再适用)。
  • -printcompilation:输出被即时编译器编译的方法信息。
3.2.3 jmap:导出内存映像文件&内存使用情况

jmap 用于生成堆内存映射或堆转储文件(heap dump)。这些文件可以用于后续的堆分析,帮助开发者诊断内存泄漏、内存溢出等问题。

jmap [option]
其中, 是要分析的 Java 进程的进程 ID。

参数选项:

  • -heap:打印出堆内存的概要信息,包括各代(新生代、老年代)的使用情况、GC 配置等。
  • -histo:打印堆内存的直方图,列出每个类的实例数量和总字节大小。帮助识别哪些类占用了大量内存。
  • -dump::生成堆转储文件。 可以是 live(仅转储活动的对象)、format=b(二进制格式)、file=(指定转储文件的名称)。
3.2.4 jinfo:实时查看和修改JVM配置参数

jinfo 用于实时查看和修改运行中的 Java 进程的 JVM 配置参数。
jinfo [option]
参数选项:

  • -flag 打印指定名称的 VM 标志的值
  • -flag [+|-] 启用或禁用指定名称的 VM 标志
  • -flag =将指定名称的 VM 标志设置为给定值
  • -Flags 打印 VM 标志
  • -sysprops 打印 Java 系统属性
  • <no option> 同时打印以上两者
  • -h 或 -help 打印此帮助信息
    注意:jinfo 在 Java 9 及更高版本中才支持参数动态修改,并且并非所有 VM 标志都支持动态修改。修改某些标志可能需要 JVM 重启才能生效。
3.2.5 jstack:打印JVM中线程快照

jstack(JVM Stack Trace):用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。

线程快照就是当前虚拟机内指定进程的每一条线程正在执行的方法堆栈的集合。可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。就可以用jstack显示各个线程调用的堆栈情况。

jstack
参数选项:

  • -F:强制生成线程堆栈。当 jstack 没有响应(进程挂起)时使用。
  • -m:如果调用到本地方法的话,可以显示C/C++的堆栈
  • -l:打印关于锁的额外信息。

4.第三方JVM监控及诊断工具

使用命令行工具或组合能帮您获取目标Java应用性能相关的基础信息,但它们无法获取方法级别的分析数据,如方法间的调用关系、各方法的调用次数和调用时间等(这对定位应用性能瓶颈至关重要)。而且结果展示不够直观。

你可以如此可爱
  为此,JDK提供了一些内存泄漏的分析工具,如jconsole,jvisualvm等,用于辅助开发人员定位问题,但是这些工具很多时候并不足以满足快速定位的需求。

4.1 eclipse MAT

MAT: MAT(Memory Analyzer Tool): 基于Eclipse的内存分析工具,是一个快速、功能丰富的Java heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。
官网下载地址:https://eclipse.dev/mat/downloads.php

4.2 阿里 Arthas

Arthas:Alibaba开源的Java诊断工具。
官方使用教程:https://arthas.aliyun.com/
功能特性:

  • 支持在线排查,无需重启

  • 动态跟踪Java代码

  • 实时监控JVM状态

  • 当你遇到以下类似问题时,Arthas可以帮助你解决(根据学习资料整理):

  • 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
    修改的代码是否生效?难道没commit?或者分支搞错了?
    遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
    线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!

  • 如何以全局视角来查看系统的运行状况?

  • 有什么办法可以监控到JVM的实时运行状态?

  • 怎么快速定位应用的热点,生成火焰图?

  • 相关诊断指令:https://arthas.aliyun.com/doc/commands.html

  • 用户案例:https://github.com/alibaba/arthas/issues?q=label%3Auser-case

5.如何设置JVM调优参数?

JVM标准参数选项
通常用于显示版本信息或帮助文档。例如:

  • -version:输出JVM的版本信息。
  • -X参数选项:通常用于调试、性能调优或诊断。例如:
  • -Xms:设置JVM初始堆大小。
  • -XX参数选项:用于调整JVM的内部行为、性能优化、诊断等。
  • -XX:+PrintGCDetails:输出详细的垃圾回收日志。
    常用的JVM参数
5.1. 设置堆、栈、方法区等内存大小
  • -Xmx4g: 设置进程占用的最大堆空间大小为4GB,超出后会导致OutOfMemoryError。
  • -Xms2g: 设置初始化堆空间大小为2GB。
  • -Xmn1g: 设置年轻代大小为1GB,官方推荐配置为整个堆的3/8。
  • -XX:NewRatio=n: 设置年轻代和老年代空间大小的比值。
  • -Xss512k: 设置每个线程占用的内存大小为512KB。
  • -XX:SurvivorRatio=n: 设置年轻代中Eden区与Survivor区的比值,例如n=4时,Eden和Survivor的比值为4:2。
  • -XX:MetaspaceSize=512m: 设置元空间(Metaspace)的初始大小为512MB。
  • -XX:MaxMetaspaceSize=512m: 设置元空间(Metaspace)增长的上限,防止无限制地使用本地内存。
  • -XX:MinMetaspaceFreeRatio=N: 设置Metaspace GC后空闲空间的最小比例,控制Metaspace的增长速度。
  • -XX:MaxMetaspaceFreeRatio=N: 设置Metaspace GC后空闲空间的最大比例,控制Metaspace的释放。
  • -XX:MaxMetaspaceExpansion=N: 设置Metaspace增长时的最大幅度。
5.2. 设置垃圾收集器
  • -XX:+UseSerialGC: 设置使用串行收集器。
  • -XX:+UseParallelGC: 设置使用并行收集器。
  • -XX:+UseParalledlOldGC: 设置使用并行年老代收集器。
  • -XX:+UseConcMarkSweepGC: 设置使用并发收集器。
  • -XX:ParallelGCThreads=n: 设置并行收集器使用的线程数。
  • -XX:MaxGCPauseMillis=n: 设置并行收集的最大暂停时间。
  • -XX:GCTimeRatio=n: 设置垃圾回收时间占程序运行时间的百分比,1/(1+n)。
  • -XX:+DisableExplicitGC: 禁止外部调用System.gc()。
  • -XX:MaxTenuringThreshold: 设置年轻代对象复制到老年代前的最大复制次数。
5.3. 垃圾回收信息统计
  • -XX:+PrintGC: 打印垃圾回收信息。
  • -XX:+PrintGCDetails: 打印详细的垃圾回收信息。
  • -XX:+PrintGCTimeStamps: 打印每次垃圾回收前程序未中断的执行时间。
  • -Xloggc:filename: 把GC日志存入指定文件。
  • -XX:+PrintGCApplicationStoppedTime: 打印垃圾回收期间程序暂停的时间。
  • -XX:+PrintGCApplicationConcurrentTime: 打印每次垃圾回收前程序未中断的执行时间。
  • -XX:+PrintHeapAtGC: 打印GC前后的详细堆栈信息。
  • -XX:+HeapDumpOnOutOfMemoryError: 在OutOfMemoryError时生成堆转储。
  • -XX:HeapDumpPath=/dump: 设置堆转储文件的路径。
5.4. 如何设置JVM运行参数?

通常应用一般部署在Linux系统中。设置JVM运行参数通常涉及在启动Java应用程序时通过命令行传递参数。这些参数可以直接附加在java命令后面,或者通过环境变量来设置。

  • 命令行设置
    例如,要设置初始堆大小为512MB和最大堆大小为1024MB,可以使用命令行:
    java -jar -Xms512m -Xmx1024m App.jar
    其中,-Xms 和 -Xmx 分别是设置初始堆大小和最大堆大小的参数,App 是你的Java应用程序的类名。

  • 环境变量设置
    可以通过设置JAVA_OPTS环境变量来做到这一点:
    export JAVA_OPTS=“-Xms512m -Xmx1024m”
    java $JAVA_OPTS App
    或者,如果你使用Tomcat应用服务器,可以在tomcat/bin/catalina.sh启动脚本中设置CATALINA_OPTS或相应的环境变量。

  • 参数选择依据
    当选择JVM参数时,可以考虑以下几点:

    • 内存需求:根据应用程序的需求,设置-Xms(初始堆大小)和-Xmx(最大堆大小)参数。

    • 垃圾收集器:使用-XX:+UseConcMarkSweepGC、-XX:+UseParallelGC、-XX:+UseG1GC等参数来选择适合的应用程序的垃圾收集器。

    • 性能调优:使用-XX:+PrintGC、-XX:+PrintGCDetails等参数来打印垃圾收集日志,帮助了解应用程序的性能,并进行调优。

    • 诊断:使用-XX:+HeapDumpOnOutOfMemoryError、-XX:HeapDumpPath=/path/to/dump等参数来在发生OutOfMemoryError时生成堆转储文件,便于后续分析。

    • 线程数:如果你的应用程序是多线程的,考虑使用-XX:ParallelGCThreads和-XX:ConcGCThreads来设置并行和并发垃圾收集器的线程数。

    • 预测试:在生产环境部署之前,模拟业务场景和硬件设备,在测试环境中验证所选参数的效果,确保它们能够满足应用程序的需求。

    • 官方文档和社区:当然,可以参考Oracle官方文档和Java社区的建议,了解参数的最佳实践和使用场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值