JVM调优学习笔记(一)

一、GC性能参数

系统的性能可以从三个维度进行衡量:

  • Latency(延迟)
  • Throughput(吞吐量)
  • Capacity(系统容量)

延迟

  • 所有交易必须在10秒内得到响应

以上就是一个延迟指标,对于这类指标,需要确保在交易过程中, GC暂停不能占用太多时间。

bash 复制代码
2015-06-04T13:34:16.974-0200: 2.578: [Full GC (Ergonomics)
        [PSYoungGen: 93677K->70109K(254976K)] 
        [ParOldGen: 499597K->511230K(761856K)] 
        593275K->581339K(1016832K),
        [Metaspace: 2936K->2936K(1056768K)]
    , 0.0713174 secs]
    [Times: user=0.21 sys=0.02, real=0.07 secs

从上方的GC日志中可见,当前事件将应用线程暂停了0.0713174秒(real)。

吞吐量

  • 解决方案每天必须处理 100万个订单

以上是一个吞吐量指标,吞吐量需求是在给定的时间内, 系统必须完成多少个操作。因此,和延迟需求类似, GC调优也需要确定GC行为所消耗的总时间。在上方的日志中可见,0.23s(user + sys = 0.21 + 0.02 s)是这段时间内 GC 暂停占用 cpu 资源的时间。

系统容量

系统容量(Capacity)需求,是在达成吞吐量和延迟指标的情况下,对硬件环境的额外约束。

二、简单的调优实验

在启动程序时,可以通过以下参数打开GC日志:

bash 复制代码
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:C:\Producer_gc.log

基于日志中的信息, 可以通过三个优化目标来提升性能:

  1. 确保最坏情况下,GC暂停时间不超过预定阈值(延迟)
  2. 确保线程暂停的总时间不超过预定阀值(吞吐量)
  3. 在确保达到延迟和吞吐量指标的情况下, 降低硬件配置以及成本(容量)

堆内存大小 和 GC算法 是程序运行时可选择的部分参数:

堆内存大小(Heap) GC算法(GC Algorithm) 有效时间比(Useful work) 最长停顿时间(Longest pause)
-Xmx12g -XX:+UseConcMarkSweepGC 89.8% 560 ms
-Xmx12g -XX:+UseParallelGC 91.5% 1,104 ms
-Xmx8g -XX:+UseConcMarkSweepGC 66.3% 1,610 ms

三、JVM分区

JVM监控工具是定位问题的有效方法,在学习监控工具前,需要理解"新生代"和"老生代"的含义。常说的 新生代(Young Generation) 和 老年代(Old Generation) ,本质上是 按对象生命周期特征划分的两块堆内存区域:

  • 新生代 :主要存放刚创建不久、生命周期短的对象
  • 老年代 :主要存放经历过多次垃圾回收后仍然存活、生命周期较长的对象

JVM 采用了经典的 分代收集思想(Generational Collection) :

  • 对大量短命对象 ,用频繁但成本较低的方式回收(Young GC)
  • 对少量长寿对象 ,用相对更重但不那么频繁的方式回收(Full GC)

JVM 运行 Java 程序时,内存是按对象生命周期和用途进行分区管理:

  • Eden:新对象最先分配的地方
  • Survivor:在 Young GC 后仍然存活的对象暂存区
  • Old(Old Generation) :存放长期存活对象
  • Metaspace:存放类元数据,不在 Java 堆里,使用本地内存
css 复制代码
Java Heap
├── Young Generation
│   ├── Eden
│   ├── Survivor From
│   └── Survivor To
└── Old Generation

Non-Heap
└── Metaspace

通过观察不同分区的使用情况,可以帮助我们定位问题。

四、JVM监控工具

以下是常用的JVM监控工具:

1、jps

jps 是 JDK 自带的一个 Java 进程查看工具,常用参数包括:

bash 复制代码
jps    # 只输出PID和主类名
jps -l # 输出完整类名 / Jar 路径
jps -m # 输出传给 main 方法的参数
jps -v # 输出 JVM 参数
jps -q # 只输出 PID,适用于脚本处理

jps 命令只会输出 Java 进程信息,输出内容精简,便于查看。

2、jstat

bash 复制代码
jstat [option] <vmid> [interval] [count]
  • interval:执行间隔时间
  • count:执行次数

常用 jstat 命令包括:

-gc

-gc 命令可以查看堆各区域容量与使用量,jstat -gc 12345命令输出的结果如下:

bash 复制代码
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
16384.0 17920.0  0.0    0.0   262144.0 132572.2  197120.0   24724.2   59160.0 55833.9 8232.0 7676.9      8    0.051   3      0.155    0.206
  • S0C / S1C:Survivor0 / Survivor1 容量
  • S0U / S1U:Survivor0 / Survivor1 已使用大小
  • EC / EU:Eden 容量 / 已使用大小
  • OC / OU:Old 区容量 / 已使用大小
  • MC / MU:Metaspace 容量 / 已使用大小
  • CCSC / CCSU:Compressed Class Space 容量 / 已使用大小
  • YGC / YGCT:Young GC 次数 / Young GC 总耗时
  • FGC / FGCT:Full GC 次数 / Full GC 总耗时
  • GCT:GC 总耗时

-gcutil

快速查看各区域使用率百分比,相比-gc,该方法输出内容更加简洁直观:

bash 复制代码
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00  50.57  12.54  94.38  93.26      8    0.051     3    0.155    0.206
  • S0 / S1:Survivor 区使用率
  • E:Eden 区使用率
  • O:Old 区使用率
  • M:Metaspace 使用率
  • CCS:Compressed Class Space 使用率
  • YGC / YGCT:Young GC 次数 / 耗时
  • FGC / FGCT:Full GC 次数 / 耗时
  • GCT:GC 总耗时

-gccapacity

查看 JVM 各区域当前容量、最小值、最大值

bash 复制代码
 NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC
 86016.0 1374720.0 280064.0 14848.0 17408.0 245248.0   172032.0  2749952.0   204800.0   204800.0      0.0 1099776.0  59160.0      0.0 1048576.0   8232.0      8     3
  • NGCMN / NGCMX:年轻代最小容量 / 年轻代最大容量
  • NGC:当前年轻代总容量
  • S0C / S1C:Survivor 0 容量 / Survivor 1 容量
  • EC:Eden 区当前容量
  • OGCMN / OGCMX:老年代最小容量 / 老年代最大容量
  • OGC / OC:当前老年代容量
  • MCMN / MCMX:Metaspace 最小容量 / Metaspace 最大容量
  • MC:当前 Metaspace 容量
  • CCSMN / CCSMX:Compressed Class Space 最小容量 / 最大容量
  • CCSC:当前 Compressed Class Space 容量
  • YGC:Young GC 次数
  • FGC:Full GC 次数

-gcnewcapcity和-gcoldcapacity可以专注于查看新生代、老年代的使用情况

-class

查看类加载情况

bash 复制代码
Loaded  Bytes  Unloaded  Bytes     Time
 13233 23485.6        0     0.0       6.95
  • Time:已加载类耗时

五、简单的GC监控实验

jstat是监控GC的最常用工具,对于 jstat 常用的参数,可以通过jstat -options查看。

执行 jstat -gc -t 2428 1s 可以让 jstat 每秒向标准输出输出一行新内容:

bash 复制代码
Timestamp  S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
200.0    8448.0 8448.0 8448.0  0.0   67712.0  67712.0   169344.0   169344.0  21248.0 20534.3 3072.0 2807.7     34    0.720  658   133.684  134.404
201.0    8448.0 8448.0 8448.0  0.0   67712.0  67712.0   169344.0   169343.2  21248.0 20534.3 3072.0 2807.7     34    0.720  662   134.712  135.432
202.0    8448.0 8448.0 8102.5  0.0   67712.0  67598.5   169344.0   169343.6  21248.0 20534.3 3072.0 2807.7     34    0.720  667   135.840  136.559
203.0    8448.0 8448.0 8126.3  0.0   67712.0  67702.2   169344.0   169343.6  21248.0 20547.2 3072.0 2807.7     34    0.720  669   136.178  136.898
204.0    8448.0 8448.0 8126.3  0.0   67712.0  67702.2   169344.0   169343.6  21248.0 20547.2 3072.0 2807.7     34    0.720  669   136.178  136.898
205.0    8448.0 8448.0 8134.6  0.0   67712.0  67712.0   169344.0   169343.5  21248.0 20547.2 3072.0 2807.7     34    0.720  671   136.234  136.954
206.0    8448.0 8448.0 8134.6  0.0   67712.0  67712.0   169344.0   169343.5  21248.0 20547.2 3072.0 2807.7     34    0.720  671   136.234  136.954
207.0    8448.0 8448.0 8154.8  0.0   67712.0  67712.0   169344.0   169343.5  21248.0 20547.2 3072.0 2807.7     34    0.720  673   136.289  137.009
208.0    8448.0 8448.0 8154.8  0.0   67712.0  67712.0   169344.0   169343.5  21248.0 20547.2 3072.0 2807.7     34    0.720  673   136.289  137.009

jstat 的输出可以体现很多问题:

  • 最后一列 GCT , 与JVM的总运行时间 Timestamp 的比值, 就是GC 的开销。如果每一秒内, GCT 的值都会明显增大, 与总运行时间相比, 就暴露出GC开销过大的问题. 一般来讲, 超过10%的GC开销都是有问题的。
  • YGC 和 FGC 列的快速变化往往也是有问题的征兆。频繁的GC暂停会累积,并导致更多的线程停顿(stop-the-world pauses), 进而影响吞吐量。
  • 如果看到 OU 列中,老年代的使用量约等于老年代的最大容量(OC), 并且不降低的话, 就表示虽然执行了老年代GC, 但基本上属于无效GC。
相关推荐
智驭未来掌门人几秒前
CLion 创建并运行 Qt 项目指南
后端
数据库小学妹4 分钟前
OLAP数据库怎么选、怎么优化?路线、提速与边界
运维·数据库·后端
加洛斯4 分钟前
万字推演Elasticsearch修炼方法,从炼气到元婴
后端·elasticsearch·面试
当时只道是寻常_9 分钟前
WorkBuddy中调用本地ComfyUi工作流免费生图
后端
用户394995084639 分钟前
Python 导入机制实战:改了代码为什么不生效
后端
房西杭10 分钟前
GM指令:add_exp 增加经验
后端
武子康11 分钟前
HunyuanVideo-1.5 首帧视频怎么做提示词对照?先查清 rewrite 是否生效
人工智能·后端·agent
今天早睡12 分钟前
用 Command 同时更新 State 与控制路由
后端
智驭未来掌门人21 分钟前
Qt开发者不是只能选Qt creator
后端
薛定谔的悦24 分钟前
从一次逆流事故说起:储能 EMS 里的 System V 信号量与跨模块快速响应机制
后端