Java性能优化JVM篇

Java性能优化 · JVM篇

关于 JVM 有一本非常经典的书籍,周志明老师的《深入理解 Java 虚拟机》,本篇的内容在该书中几乎都能找到,我也写了关于本书的读书笔记,经典图书-深入理解Java虚拟机

本来想重新整理一下,想了想还是 Don’t repeat yourself,关于内存模型、即时编译、垃圾回收和 GC,在读书笔记中都整理过了。

image-20260704164830311

因此这里不再重复,只介绍下 Java 内存问题的排查路径,当然还是要先介绍一些前置知识。

对象生存周期

  • 新建对象优先分配到 Eden 区
  • 对象有对象年龄计数器-XX:MaxTenuringThreshold 设置)
  • Eden 空间不足时,JVM 执行 Minor GC,将存活对象转移到 Survivor 中,年龄 +1
  • 对象在 Survivor 中经历 Minor GC,每经过一次 Minor GC,年龄 +1
  • 可通过 -XX:PetenureSizeThreshold 设置直接被分配到老年代的最大对象阈值

JVM 堆内存分配默认值

1
2
java -XX:+PrintFlagsFinal -version | grep HeapSize
jmap -heap <pid>

JDK 1.7 默认比例

  • 年轻代 : 老年代 = 1 : 2(可通过 -XX:NewRatio 重置)
  • Eden : To Survivor : From Survivor = 8 : 1 : 1(可通过 -XX:SurvivorRatio 重置)

JDK 1.8

  • 默认开启 -XX:+UseAdaptiveSizePolicy,JVM 动态调整 Java 堆各区域大小以及进入老年代的年龄
  • 开启自适应策略后,-XX:NewRatio-XX:SurvivorRatio 将会失效
  • **不要随便关闭 UseAdaptiveSizePolicy**,除非已对堆内存/年轻代/老年代/Eden/Survivor 有非常明确的规划,否则 JVM 将分配最小堆内存,默认比例分配未必是最佳配置

JVM 内存分配不合理最直接的表现是频繁的 GC,导致上下文切换等性能问题,降低系统吞吐量、增加响应时间。在线上或性能测试时发现频繁 GC(且是正常的对象创建和回收),就需要考虑调整 JVM 内存分配。

Linux 命令行工具

top 命令

1
2
top
top -Hp <pid> # 查看具体线程使用系统资源情况

实时显示 CPU 使用率、内存使用率、系统负载等信息。

vmstat 命令

  • 指定采样周期和次数的功能性监测工具
  • 不仅统计内存使用,还可观测 CPU 使用率、swap 使用情况
  • 经常被用来观察进程的上下文切换

关键字段r(等待运行进程数)、b(非中断睡眠进程数)、swpd(虚拟内存)、free(空闲内存)、si/so(交换页数量)、bi/bo(块设备块数)、in(每秒中断数)、cs(每秒上下文切换次数)、us/sy/id/wa/st(CPU 时间)

pidstat 命令(Sysstat 组件,yum install sysstat):

1
2
pidstat -p <pid> -r 1 3       # 监控内存
pidstat -p <pid> -t # 查看线程级内存使用率
参数 说明
-u 默认参数,显示各进程 CPU 使用情况
-r 显示各进程内存使用情况
-d 显示各进程 I/O 使用情况
-w 显示每个进程的上下文切换情况
-p 指定进程号
-t 显示进程中线程的统计信息

关键指标Minflt/s(次要错误)、Majflt/s(主要错误)、VSZ(虚拟地址大小)、RSS(常驻集合大小)

JDK 工具

jstat 命令

1
jstat -gc <pid>                # 查看堆内存使用情况
  • -class:显示 ClassLoad 信息
  • -compiler:显示 JIT 编译信息
  • -gc:显示和 gc 相关的堆信息
  • -gccapacity:显示各代容量及使用情况
  • -gcmetacapacity:显示 Metaspace 大小
  • -gcnew:显示新生代信息
  • -gcnewcapacity:显示新生代大小和使用情况
  • -gcold:显示老年代和永久代信息
  • -gcoldcapacity:显示老年代大小
  • -gcutil:显示垃圾收集信息
  • -gccause:显示 GC 相关信息和诱因
  • -printcompilation:输出 JIT 编译方法信息

jstat -gc 输出字段

  • S0C/S1C:年轻代 To/From Survivor 容量
  • S0U/S1U:年轻代 To/From Survivor 已使用空间
  • EC/EU:年轻代 Eden 容量/已使用空间
  • OC/OU:Old 代容量/已使用空间
  • MC/MU:Metaspace 容量/已使用空间
  • YGC/YGCT:年轻代 GC 次数/总时间
  • FGC/FGCT:Full GC 次数/总时间
  • GCT:GC 用的总时间

jstack 命令

1
jstack <pid>

线程堆栈分析工具,查看线程堆栈信息、线程 ID、状态(wait/sleep/running)、是否持有锁,常与 top -Hppidstat -p -t 结合使用,常用于排查死锁异常

jmap 命令

1
2
3
jmap -heap <pid>                       # 查看堆内存初始化配置及使用情况
jmap -histo[:live] <pid> # 查看堆内存中对象数目、大小统计直方图
jmap -dump:format=b,file=heap.hprof <pid> # dump 堆内存到文件

注意:dump 出的文件用 MAT(Memory Analyzer Tool) 工具分析。

内存溢出 vs 内存泄漏

概念 说明
内存泄漏 不再使用的对象无法及时回收,持续占用内存空间,造成浪费(如 Java 6 substring 复用原 char 数组导致大字符串无法回收)
内存溢出(OOM) 发生 OutOfMemoryException,堆内存、栈、方法区空间不足时发生
关系 内存泄漏很容易导致内存溢出,但内存溢出不一定是内存泄漏导致

关键调优参数

内存相关

参数 说明
-Xms 堆初始大小
-Xmx 堆最大值
-Xmn 年轻代大小
-XX:NewRatio 年轻代与老年代比例
-XX:SurvivorRatio Eden 与 Survivor 区比例
-XX:MaxTenuringThreshold 对象年龄计数器阈值
-XX:PetenureSizeThreshold 直接分配到老年代的最大对象阈值
-XX:MetaspaceSize 元空间大小
-XX:+UseAdaptiveSizePolicy 开启自适应大小策略(JDK 1.8 默认开启)

JIT 编译相关

参数 说明
-client / -server 强制指定 JIT 模式(Java 8 后无效)
-XX:+TieredCompilation 开启分层编译(默认)
-XX:-TieredCompilation 关闭分层编译,只用 C2
-XX:TieredStopAtLevel=1 分层编译时只用 C1
-Xint 强制只有解释器
-Xcomp 强制只有 JIT
-XX:CompileThreshold=N 方法调用计数器阈值
-XX:OnStackReplacePercentage=N 回边计数器阈值
-XX:MaxFreqInlineSize=N 经常执行方法的内联大小(默认 325 字节)
-XX:MaxInlineSize=N 非经常执行方法的内联大小(默认 35 字节)

JIT 优化相关

参数 说明
-XX:+DoEscapeAnalysis 开启逃逸分析(默认)
-XX:+EliminateLocks 开启锁消除(默认)
-XX:+EliminateAllocations 开启标量替换(默认)
-XX:+PrintCompilation 打印编译过程信息
-XX:+UnlockDiagnosticVMOptions 解锁 JVM 诊断选项
-XX:+PrintInlining 打印内联方法

GC 相关

参数 说明
-XX:+PrintGC 输出 GC 日志
-XX:+PrintGCDetails 输出 GC 详细日志
-XX:+PrintGCTimeStamps 输出 GC 时间戳(基准时间)
-XX:+PrintGCDateStamps 输出 GC 时间戳(日期形式)
-XX:+PrintHeapAtGC GC 前后打印堆信息
-Xloggc:./gclogs 日志文件输出路径
-XX:InitiatingHeapOccupancyPercent=N G1 触发 Mix GC 的堆占用阈值(默认 45)
-XX:MaxGCPauseMillis=N G1 目标停顿时间(默认 200ms)

OOM Dump 相关

参数 说明
-XX:+HeapDumpOnOutOfMemoryError 堆内存异常时 dump
-XX:HeapDumpPath=/tmp/heapdump.hprof dump 文件路径

一定要注意:JVM 调优先观察后动手,默认配置在大部分场景下效果都不错,一定要基于监控数据(top、vmstat、pidstat、jstat、jstack、jmap)和 GC 日志调整。


Java性能优化JVM篇
https://zhuwenjie0716.github.io/2026/07/06/Java性能优化JVM篇/
作者
Wenjie Zhu
发布于
2026年7月6日
许可协议