JVM工厂运行说明书
# JVM工厂运行说明书
面向脑内“工厂”心智模型,对JVM的关键概念、运行流程与调优方法做一体化说明:从“进货入库”(类加载/元空间)到“下单生产”(对象创建/执行引擎),再到“成品仓储”(堆/分代)与“清洁巡检”(GC/收集器),最后覆盖“监控仪表与应急预案”(参数/日志/工具)。
# 0. 工厂总览(术语对照)
- 原料进货/入库:类加载(加载→验证→准备→解析→初始化)
- 原料仓/货架:元空间/方法区(类元数据、常量池、方法/字段信息等)
- 运输/物流:类加载器体系(引导/扩展/应用/自定义,双亲委派)
- 生产订单:
new
一个对象/方法调用 - 生产车间:执行引擎 + 线程方法栈 + 栈帧(局部变量表、操作数栈、动态链接、返回地址)
- 流水线工艺:字节码指令集(操作数栈驱动)、静态初始化/构造过程
- 质检/打标:零值初始化、对象头(MarkWord、Klass Pointer、对齐)
- 成品仓储:堆(新生代/老年代、Eden/Survivor、晋升/大对象)
- 客户/占用标签:引用类型(强/软/弱/虚)、可达性分析、GC Roots
- 清洁巡检:GC算法(复制、标记-清除、标记-整理)、三色标记与屏障、记忆集/卡表
- 设备选型:收集器(Serial/Parallel/ParNew/CMS/G1)与参数
- 仪表盘:JVM启动参数、GC日志、jstat/jmap/jstack/jinfo、MAT
- 应急与优化:OOM转储、参数与收集器策略、案例化分析
# 1. 进货与入库:类加载 → 元空间/方法区
流程(loadClass):加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载。
- 加载:按需读取
.class
字节码,生成java.lang.Class
对象(堆中),作为方法区类元数据的访问入口。 - 验证:字节码合法性/安全性校验。
- 准备:为静态变量分配内存并赋零值。
- 解析:符号引用 → 直接引用(静态链接),运行期仍可动态链接。
- 初始化:执行静态变量赋值与
<clinit>
静态代码块。
方法区/元空间存放:运行时常量池、类型/字段/方法信息、类加载器引用、对应Class
实例引用等。
类加载器与双亲委派:
- 引导(Bootstrap,C++实现)、扩展(Ext)、应用(App)、自定义(继承
ClassLoader
,重写findClass
)。 - 双亲委派:先问“父亲”,加载不到再“儿子”。好处:沙箱安全、避免重复加载、保证唯一性。
- 打破/定制:容器(如Tomcat)为实现“多应用隔离/共享、JSP热加载”等,构建自定义类加载器层次,必要处打破默认委派,但仍尊重JDK核心类的沙箱边界。
示例与要点(摘自 01.JVM类的加载机制):
- Demo:打印各级类加载器与加载路径;
Launcher.getBootstrapClassPath()
列举引导类加载路径。 - 源码骨架:
ClassLoader#loadClass
先findLoadedClass
,再委派父加载器,最顶层失败后回落到子加载器findClass
。 - Tomcat类加载器体系:
commonLoader
(容器与各Webapp可见)、catalinaLoader
(容器私有)、sharedLoader
(Webapp共享)、WebappClassLoader
(每war私有,可隔离不同依赖版本与支持JSP热加载)。 - 打破委派的动机:同一JVM内允许“相同类名+不同类加载器”并存,避免类版本冲突/重复加载,满足应用隔离与热替换。
- 注意:判断“同一个类”需同时比较“类全名+类加载器实例”。
类卸载(无用类判定):无实例、加载它的ClassLoader可回收、Class
对象不可达且不可反射访问。
# 2. 下单与生产:对象创建与执行流水线
对象创建(new
)五步:
- 加载检查:常量池能定位到类的符号引用,且已加载/解析/初始化,否则先触发类加载流程。
- 分配内存(堆):
- 指针碰撞(默认,堆规整时);空闲列表(堆不规整时)。
- 并发安全:CAS+失败重试 或 TLAB(每线程本地分配缓冲,
-XX:+UseTLAB
)。
- 零值初始化:为实例字段赋零值(不含对象头)。
- 设置对象头:MarkWord(HashCode、年龄、锁状态、偏向线程ID、时间戳等)、Klass Pointer(类元数据指针)、对齐填充。
- 执行
<init>
:按程序员意愿赋值与构造逻辑(区别于零值初始化)。
指针压缩(64位内存占用优化):
UseCompressedOops
(普通对象指针)、UseCompressedClassPointers
(类指针)。堆≤32G场景显著提升对象密度;>32G将失效转为8字节寻址。
逃逸分析与栈上分配:
-XX:+DoEscapeAnalysis
配合-XX:+EliminateAllocations
,将不逃逸的聚合对象拆为标量放入栈帧/寄存器,减少堆分配与GC压力。
执行流水线(字节码/操作数栈):
- 方法执行创建栈帧(局部变量表、操作数栈、动态链接、返回地址)。
- 指令示例:
iload/istore
(变量和栈交互)、invokestatic/invokevirtual
(调用)、if_acmpne/goto
(跳转)。
字节码观察要点(摘自 10.字节码与操作数栈):
stack/locals/args_size
:分别代表最大操作数栈深度、局部变量表槽位数、形参数量。LineNumberTable
:源代码行号与指令偏移映射;调试/采样分析用。LocalVariableTable
:局部变量在字节码生命周期内的作用域、名称与槽位索引。StackMapTable
:类型验证与快速校验框架,JDK7开始对ClassFile验证很关键。- 自动装箱/缓存示例:
Integer.valueOf
缓存[-128,127],==
对比引用将出现10相等、128不等;Boolean.valueOf
仅缓存TRUE/FALSE;Double
不缓存一般数值。
对象头与对齐(摘自 03.JVM对象创建与内存分配机制):
- MarkWord:哈希码、分代年龄、锁状态标志、偏向线程ID、时间戳。
- Klass Pointer:指向类元数据;压缩类指针启用后由8字节压至4字节。
- 对齐填充:对象尺寸按8字节对齐以优化寻址与缓存利用。
分配细节与并发安全:
- 内存划分:指针碰撞(规整堆更快)、空闲列表(非规整堆需维护空闲链)。
- 并发:CAS失败重试 或 TLAB按线程预配(
-XX:+UseTLAB
默认开启,-XX:TLABSize
可调)。
指针压缩联动关系(关键结论):
- 开启
UseCompressedOops
通常会强制开启UseCompressedClassPointers
;若仅开类指针压缩而关Oops会报错(类指针压缩依赖Oops压缩)。 - 小对象示例:在开启压缩下,引用字段与klass指针从8→4字节,提升堆密度。
示例:栈上分配与逃逸分析压力测试(见 03 文内 AllotOnStack 示例)
- 关键参数:
-Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+PrintGC
- 关闭任意一项(逃逸分析或标量替换)将显著增加堆分配与GC次数。
# 3. 成品仓储:堆内存分代与晋升策略
新生代(Eden + From/To Survivor)与老年代:
- 绝大多数对象“朝生夕死”,Eden满触发Minor GC;幸存对象在S区间来回复制并增长年龄;达到阈值(
MaxTenuringThreshold
,默认15;CMS常为6)晋升老年代。 - 动态年龄判断:当某S区内各年龄段对象总和超目标(
TargetSurvivorRatio
默认50%),≥该最大年龄的对象提前晋升。 - 大对象:超过
-XX:PretenureSizeThreshold
(仅Serial/ParNew生效)直接进老年代,避免新生代复制成本。 - 空间分配担保:Minor GC前评估老年代可用空间与历史晋升均值,必要时触发Full GC以担保复制与晋升安全。
堆大小与代际比例:
-Xms/-Xmx
堆初始/最大,-Xmn
新生代,-XX:NewRatio
新老比,-XX:SurvivorRatio
S:Eden比(默认8:1:1)。- 建议尽量让对象在新生代分配与回收,减少老年代压力与Full GC频率。
引用与可达性:
- 强/软/弱/虚引用;GC Roots(线程栈、本地方法栈、静态字段等);可达性分析决定存活性。
finalize()
仅作二次标记的“自救”机会,业务上尽量避免依赖。
GC触发条件(摘自 02.JVM内存模型):
- Minor GC:Eden满。
- Full GC:System.gc()建议;老年代空间不足;方法区(元空间)不足;Minor后晋升均值超出老年代可用;复制到To Survivor溢出转入老年代且老年代不足;空间担保失败等。
新生代与S区比例:
-XX:NewRatio
(例如4→新:老=1:4)、-XX:SurvivorRatio
(例如8→(S0+S1):Eden=2:8)。-XX:+UseAdaptiveSizePolicy
默认自适应,若需稳定8:1:1可关闭该策略。
# 4. 清洁巡检:GC算法与实现细节
分代收集思想:不同存活特征采用不同算法。
- 复制(新生代):空间换时间,吞吐高。
- 标记-清除(老年代):快但有碎片。
- 标记-整理(老年代):消碎片但更耗时。
并发标记中的三色标记与屏障:
- 三色:白(未达)、灰(达未扫完)、黑(达且已扫)。
- 漏标与多标:
- 增量更新(CMS):写屏障记录“黑→白”新增引用,重标记回扫这些黑对象。
- SATB(G1/Shenandoah):写屏障记录“灰删除对白”的旧引用,保持起始快照的一致性,重标记回扫。
- 读屏障(ZGC):通过读屏障配合转发指针解决并发移动中的可见性与一致性。
跨区引用的记忆集/卡表:
- 避免扫描非收集区全堆,对非收集区维护指向收集区的指针集合;HotSpot以卡表(512B卡页)+写屏障维护“脏卡”。
触发条件精要:
- Minor GC:Eden满。
- Full GC:老年代不足/方法区不足/混合回收失败/空间担保失败/显式
System.gc()
(建议)等。
图片索引(见原文):
- 分代与算法示意图:http://blogimg.gkmall.top/img/jvm/202305271320740.jpg 等
- 三色标记、写/读屏障图解:http://blogimg.gkmall.top/img/jvm/202305271323785.jpg 等
# 5. 设备选型:主流垃圾收集器与场景
Serial/Serial Old:单线程,Stop-The-World,简单高效但停顿长。
Parallel/Parallel Old(JDK8默认):多线程吞吐优先,年轻代复制,老年代标整。
ParNew:年轻代并行,常与CMS搭配。
CMS:最短停顿优先(老年代并发标记-清除)。优点:低停顿;缺点:浮动垃圾、碎片、并发失败回退Full GC。关键参数:
-XX:+UseConcMarkSweepGC
,-XX:CMSInitiatingOccupancyFraction
,-XX:+UseCMSInitiatingOccupancyOnly
。
G1:面向大堆、可预期停顿,Region化管理,整体标整、局部复制;Young GC/Mixed GC/Full GC三类回收,目标停顿-XX:MaxGCPauseMillis
。关键参数:
-XX:+UseG1GC
、-XX:G1HeapRegionSize
、-XX:InitiatingHeapOccupancyPercent
、-XX:G1MixedGCLiveThresholdPercent
、-XX:G1MixedGCCountTarget
、-XX:G1HeapWastePercent
、-XX:TargetSurvivorRatio
、-XX:MaxTenuringThreshold
。
选择建议(经验向):
- 吞吐优先:Parallel/Parallel Old。
- 低停顿优先(4~8G):CMS。
- 大堆与停顿可控(≥8G):G1(或更进阶的ZGC/Shenandoah但JDK版本依赖)。
G1工作流细节(摘自 05.JVM垃圾收集器):
- Region化堆(1MB~32MB,2的幂,默认2048个分区,
-XX:G1HeapRegionSize
)。 - Young GC:并非Eden一满即触发,会结合
-XX:MaxGCPauseMillis
预算决定何时回收与扩张年轻代。 - Mixed GC:并发标记后按老年代Region存活率阈值与回收收益选择一批Old Region与Young一起回收;目标次数
-XX:G1MixedGCCountTarget
;阈值-XX:G1MixedGCLiveThresholdPercent
。 - Full GC:复制失败或空Region不足时退化为单线程压缩(JDK更高版本有并行化改进)。
- 关键触发/控制:
-XX:InitiatingHeapOccupancyPercent
(并发标记的全堆占用率阈值,默认45%)。-XX:G1HeapWastePercent
(回收过程中“空出来的Region”达到堆的该比例即停止本轮混合回收,默认5%)。-XX:TargetSurvivorRatio
/-XX:MaxTenuringThreshold
影响晋升节奏与S区承载。
CMS阶段与注意点(摘自 05.JVM垃圾收集器):
- 阶段:初始标记(STW,标记GC Roots直接可达对象)→ 并发标记(与应用并发,三色标记)→ 重新标记(STW,增量更新回扫)→ 并发清理(清除未标记对象)→ 并发重置。
- 特点:低停顿但会产生浮动垃圾(并发期间新垃圾留到下轮);基于标记-清除会有碎片;并发失败将退化为STW Full GC。
- 关键参数:
-XX:+UseConcMarkSweepGC
、-XX:CMSInitiatingOccupancyFraction=<阈值>
、-XX:+UseCMSInitiatingOccupancyOnly
。
# 6. 仪表盘与运维:参数、日志与工具
常用内存/代际参数(示例以JDK8为主):
- 线程栈
-Xss
;堆-Xms/-Xmx/-Xmn
;新老比例-XX:NewRatio
;S区比例-XX:SurvivorRatio
。 - 元空间:
-XX:MetaspaceSize
(初始触发Full GC阈值,默认约21M,建议与-XX:MaxMetaspaceSize
设一致且略大于默认阈值,如256M),-XX:MaxMetaspaceSize
。 - OOM转储:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=...
。 - 容器化:
-XX:+UseContainerSupport -XX:MaxRAMPercentage=<x> -XX:InitialRAMPercentage=<x> -XX:MinRAMPercentage=<x>
。 - G1目标停顿:
-XX:MaxGCPauseMillis
(过小会混合回收跟不上,易Full GC)。
容器化与一体化示例命令(摘自 06.JVM调优工具以及调优实战):
java -XX:+UseContainerSupport \
-XX:MaxRAMPercentage=60.0 -XX:InitialRAMPercentage=60.0 -XX:MinRAMPercentage=60.0 \
-XX:NewRatio=2 -Xss512k \
-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M \
-Djava.awt.headless=true -d64 -server -Djava.net.preferIPv4Stack=true \
-Djavax.servlet.request.encoding=UTF-8 -Dfile.encoding=UTF-8 \
-XX:+AlwaysPreTouch \
-XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly \
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps \
-jar app.jar
2
3
4
5
6
7
8
9
10
- 每个参数的意义见 06 文详细注释;建议按物理/容器限额设置RAM百分比,Metaspace初始与最大设置一致并高于21M默认触发阈值。
常用jstat
指标(节选自 06 文):
-gc
:S0C/S1C/S0U/S1U、EC/EU、OC/OU、MC/MU、CCSC/CCSU、YGC/YGCT、FGC/FGCT、GCT。-gccapacity
:新生代/老年代/元空间的最小、最大、当前容量。-gcnew/-gcnewcapacity
:新生代对象年龄阈值(TT/MTT)、期望幸存区大小(DSS)等。-gcold/-gcoldcapacity
:老年代容量与回收统计。-gcmetacapacity
:元空间/压缩类空间容量与使用。
jstat
字段释义补充(整合 06 文):
-gc
:- S0C/S1C:两个Survivor区容量(KB);S0U/S1U:各自使用量;
- EC/EU:Eden容量/使用量;OC/OU:Old容量/使用量;
- MC/MU:Metaspace容量/使用;CCSC/CCSU:压缩类空间容量/使用;
- YGC/YGCT:Young GC次数/耗时(s);FGC/FGCT:Full GC次数/耗时(s);GCT:GC总耗时(s)。
-gccapacity
:- NGCMN/NGCMX/NGC:新生代最小/最大/当前;S0C/S1C/EC 同上;
- OGCMN/OGCMX/OGC/OC:老年代最小/最大/当前/当前(容量口径不同);
- MCMN/MCMX/MC:元空间最小/最大/当前;
- CCSMN/CCSMX/CCSC:压缩类空间最小/最大/当前;
- YGC/FGC:次数。
-gcnew
:- S0C/S1C/S0U/S1U、EC/EU 同上;
- TT/MTT:当前提升到老年代的年龄阈值/最大阈值;DSS:期望幸存区大小。
-gcnewcapacity
:- NGCMN/NGCMX/NGC:新生代容量边界与当前;
- S0CMX/S0C、S1CMX/S1C:两个S区最大/当前容量;ECMX/EC:Eden最大/当前容量;
- YGC/FGC:次数。
-gcold
/-gcoldcapacity
:- OC/OU:老年代容量/使用量;FGCT/GCT:耗时统计等。
-gcmetacapacity
:- MCMN/MCMX/MC:元空间;CCSMN/CCSMX/CCSC:压缩类空间;YGC/FGC/FGCT/GCT 同上。
常用jmap/jstack/jinfo
:
jmap -histo <pid>
:类实例数与占用;-heap
堆布局;-dump:format=b,file=...
导出dump。jstack <pid>
:线程栈/死锁/高CPU线程定位(结合top -Hp
与16进制TID)。jinfo -flags/-sysprops <pid>
:查看JVM参数与系统属性,部分参数可运行时调整。
GC日志判读(示例在11.GCLog分析.md
):
- 关注Young区变化、堆整体变化、晋升量=Young清理量-堆整体释放量;频繁Full GC通常意味着老年代顶不住或空间担保失败。
命令行工具(06.JVM调优工具以及调优实战.md
):
jps
(进程)、jmap
(heap直方图/堆信息/导出dump)、jstack
(线程栈/死锁/高CPU线程定位)、jinfo
(参数/部分运行时可调)、jstat
(各区使用量与GC统计,如jstat -gc
/-gccapacity
/-gcnew
/-gcold
/-gcmetacapacity
)。
GC日志开关与输出:
- JDK8常用:
-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:<file>
; - JDK9+统一日志:
-Xlog:gc*,safepoint:file=<file>:tags,uptime,time,level
; - 生产建议:固定日志文件路径并轮转,结合可视化工具(如 GC Easy)辅助判读。
高CPU线程定位步骤(整合 06 文):
top -Hp <pid>
查看线程占用;记下最高TID;- 将TID转16进制(如Linux
printf "%x\n" <tid>
); jstack <pid> | grep -A 30 <hexTid>
定位堆栈热点方法;- 结合业务日志/监控比对确认异常热点。
MAT离线分析(详见40.JVM 内存分析工具 MAT及实践.md
):
- 核心视图:Dominator Tree(支配内存/Retained Heap)、Histogram(类直方图)、Leak Suspects(疑似泄漏)、Path to GC Roots(强引用链)、Thread Overview(线程与持有对象)、Class Loader Explorer(类加载器与重复类)。
- 常见排查切入:
- 先看Dominator Tree定位“谁支配了大头内存”,再结合Histogram做聚合;
- Path to GC Roots溯源“为何不可回收”;
- Class Loader Explorer定位“过多ClassLoader/重复类版本冲突”;
- Collections工具看ArrayList填充率/HashMap冲突;
- OQL按业务条件批量筛选、导出做进一步分析。
MAT关键步骤与案例摘记(节选整合 40 文):
- Heap Dump Overview:先扫全局(对象数、ClassLoader数、GC Roots数、线程概况)。
- Dominator Tree:Top1常用入口,按package/class/classloader聚类,直击“谁在支配谁”;右键“Immediate Dominator”溯源直接支配者。
- Histogram:Top2常用入口,计算Retained Heap后排序,结合正则与分组快速锁定大头类。
- Leak Suspects:自动探测疑似泄漏点,适用于快速入手。
- Thread Overview:看线程持有对象与阻塞栈,命名规范可极大提升定位效率。
- Path To GC Roots:建议勾选“exclude all phantom/weak/soft”,聚焦强引用链。
- Class Loader Explorer / Duplicated Classes:定位ClassLoader风暴与重复类版本。
- Collections:查看ArrayList填充率、HashMap冲突,找出“占坑不放货”的空/稀疏集合。
- OQL:SELECT * FROM
WHERE ;例如: select * from java.util.ArrayList where size=0 and modCount=0
快速找空表对象;可将结果导出再做脚本分析。
# 7. 事故与优化:应急流程与调优要点
应急流程(堆飙升/频繁Full GC/OOM):
- 开启GC日志与HeapDump(若未开,复现前先配置);
- 通过
jstat -gc
观察Young/Old压力、YGC/FGC次数与耗时; jmap -histo
看对象分布大头;必要时导出jmap -dump
→MAT定位支配对象与引用链;jstack
定位可疑线程(高CPU/死锁/阻塞导致对象长时间存活)。
常见优化抓手:
- 让对象尽量在新生代“就地去世”,减小晋升与老年代压力;
- 合理设置堆/新生代大小、目标停顿时间,避免Survivor放不下触发“动态年龄判定”过早晋升;
- 大对象直配老年代仅在确有必要时启用;
- CMS场景关注碎片与并发失败,必要时压缩或转向G1;
- G1关注
MaxGCPauseMillis
、InitiatingHeapOccupancyPercent
、G1MixedGCCountTarget
等参数的均衡; - 元空间大小与触发阈值尽量一致、略高于默认以避免频繁Full GC的“抖动”。
GC日志样例要点(整合 11.GCLog分析):
- 示例行:
[PSYoungGen: 16384K->2016K(18432K)] 16384K->14294K(59392K)
- 年轻代释放:16384-2016=14368K;堆总释放:16384-14294=2090K;
- 晋升近似:14368K-2090K≈12278K(清理的年轻代-堆整体释放 ≈ 进入老年代)。
- 关注频繁Full GC:多由老年代压力/晋升过快/空间担保失败导致。
KPI观念:
- 吞吐量(总运行时间中GC占比越低越好)
- 最大停顿(客户端/延迟敏感优先)
- 内存占用(容器化/成本敏感)
# 8. 工厂隐喻一览(快速映射)
- 原料进货 → 类加载(到元空间)
- 入库上架/打标 → 验证/准备/解析/初始化
- 原料仓 → 元空间/方法区
- 运输/物流 → 类加载器/双亲委派/沙箱
- 订单下发 → new对象/方法调用
- 车间与工艺 → 执行引擎/方法栈/操作数栈/字节码
- 质检与贴标 → 零值初始化/对象头(MarkWord、Klass Pointer、对齐)
- 成品区 → 堆(Eden/Survivor/Old、晋升/大对象)
- 客户标记 → 引用类型与可达性(GC Roots)
- 清洁巡检 → GC算法(复制/标清/标整)、三色标记/屏障、记忆集/卡表
- 设备与产线 → 收集器(Serial/Parallel/ParNew/CMS/G1)
- 仪表与报警 → 启动参数/GC日志/jstat/jmap/jstack/jinfo/MAT
- 故障与应急 → OOM转储、GC调优与案例分析
# 9. 参考与延伸
- 源笔记详见当前目录各
.md
文件;其中:- 类加载与双亲委派:
01.JVM类的加载机制.md
- 内存模型与参数:
02.JVM内存模型.md
- 对象创建/分配/晋升/引用:
03.JVM对象创建与内存分配机制.md
- GC算法与三色标记/屏障/卡表:
04.JVM垃圾收集算法.md
- 收集器与G1参数:
05.JVM垃圾收集器.md
- 启动参数与运维工具:
06.JVM调优工具以及调优实战.md
- 字节码/操作数栈:
10.字节码与操作数栈.md
- GC日志解析:
11.GCLog分析.md
- MAT实战:
40.JVM 内存分析工具 MAT及实践.md
- 类加载与双亲委派:
以上内容按“工厂”主线串联,便于整体理解与实战定位。若需要,我可以基于你的运行环境与业务负载,补充“场景化参数模板”和“调优分步剧本”。
# 附录A 参数清单精选(整合 02/05/06)
- 内存与分代
-Xss<size>
:每线程栈大小(经验值3000~5000线程范围要平衡)。-Xms/-Xmx
:堆初始/最大;-Xmn
:新生代大小。-XX:NewSize
/-XX:MaxNewSize
:新生代初始/最大容量。-XX:OldSize
:老年代大小(较少直接设,通常通过整体与新生代推导)。-XX:NewRatio=<n>
:新:老=1:n(例4→1:4)。-XX:SurvivorRatio=<n>
: (S0+S1):Eden=2:n(例8→2:8)。
- 元空间/类指针
-XX:MetaspaceSize=<m>
:初始阈值(默认约21M,触发Full GC做类型卸载与阈值自调)。-XX:MaxMetaspaceSize=<m>
:最大元空间,建议与初始设为一致且略高于默认触发阈值(如256M)。-XX:+UseCompressedOops
、-XX:+UseCompressedClassPointers
:64位堆≤32G建议开启(一般默认开)。
- 收集器选择
-XX:+UseParallelGC
、-XX:+UseParallelOldGC
:吞吐优先;JDK8默认。-XX:+UseConcMarkSweepGC
:CMS老年代;-XX:CMSInitiatingOccupancyFraction=<%>
、-XX:+UseCMSInitiatingOccupancyOnly
。-XX:+UseG1GC
:大堆/可预测停顿;-XX:MaxGCPauseMillis=<ms>
、-XX:InitiatingHeapOccupancyPercent=<%>
、-XX:G1HeapRegionSize=<size>
、-XX:G1MixedGCLiveThresholdPercent=<%>
、-XX:G1MixedGCCountTarget=<n>
、-XX:G1HeapWastePercent=<%>
、-XX:TargetSurvivorRatio=<%>
、-XX:MaxTenuringThreshold=<n>
、-XX:ConcGCThreads=<n>
、-XX:G1OldCSetRegionThresholdPercent=<%>
。
- 其他关键项
-XX:+AlwaysPreTouch
:启动时预触摸堆以避免运行时缺页。-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<path>
:OOM生成dump与路径。- GC日志:JDK8
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:<file>
;JDK9+-Xlog:gc*
。 - 容器:
-XX:+UseContainerSupport -XX:MaxRAMPercentage=<x> -XX:InitialRAMPercentage=<x> -XX:MinRAMPercentage=<x>
。
# 附录B MAT综合案例简版(整合 40)
- 案例1(ClassLoader风暴/大集合持有)
- 代码要点:循环创建自定义ClassLoader加载同名类;两个线程睡眠并间接持有一个巨大的
ArrayList<Integer>
。 - 路线:
- Heap Dump Overview → 发现ClassLoader数异常、线程数/名称;
- Class Loader Explorer → 聚合定位自定义Loader;
- Dominator Tree(聚合到class)→ 找到支配内存的大类/容器;
- Path to GC Roots / incoming references → 回溯到具体创建路径;
- Collections → 验证大集合具体装载量与空间浪费。
- 代码要点:循环创建自定义ClassLoader加载同名类;两个线程睡眠并间接持有一个巨大的
- 案例2(NoClassDefFoundError/重复类)
- 路线:Java Basics → Duplicated Classes → 过滤类名 → Inspector 查看类来源jar/war → 清理冲突版本/Loader配置。
- 案例3(大量空ArrayList占用)
- OQL:
select * from java.util.ArrayList where size=0 and modCount=0
→ Histogram计算Retained Heap总量 → incoming references定位来源 → 设计懒加载或延迟初始化。
- OQL:
# 附录C 常见调优剧本(从症状出发)
- 症状:FGC频繁、老年代接近满
- 看:
jstat -gc
的OU/FGC/FGCT;GC日志FGC原因; - 做:增大堆或降低晋升速率(增大S区、调整
MaxTenuringThreshold
、合理TargetSurvivorRatio
);评估大对象直配策略;必要时从CMS切到G1。
- 看:
- 症状:YGC很频繁、单次停顿短但整体抖动
- 看:Eden大小与对象分配速率;
- 做:适度扩大新生代或放宽
MaxGCPauseMillis
目标(G1),避免过窄导致频繁Young GC。
- 症状:Metaspace触发Full GC抖动
- 做:将
MetaspaceSize
≈MaxMetaspaceSize
并高于21M默认阈值;排查频繁生成/卸载的动态类(代理/JSP)。
- 做:将
- 症状:高CPU热点线程
- 路线:
top -Hp
→十六进制TID→jstack | grep -A
→ 找热点堆栈;对代码与依赖做热点优化/限流/降级。
- 路线: