JVM 调优不是上来就改参数。真正可靠的顺序是:先确认问题,再拿到证据,再分析原因,最后小步调整并验证效果。
一句话概括:JVM 调优的核心不是背参数,而是围绕内存、GC、线程和 CPU 建立排查闭环。
JVM 参数可以在哪里设置
不同部署方式设置位置不同。
| 部署方式 | 常见设置位置 |
|---|---|
| 直接运行 jar | java 启动命令后添加 JVM 参数 |
| Shell 脚本启动 | 启动脚本中的 JAVA_OPTS 或命令行 |
| Tomcat 部署 war | catalina.sh、setenv.sh 或服务启动配置 |
| Docker 容器 | Dockerfile、启动命令、环境变量 |
| Kubernetes | Deployment 的 command、args、env |
普通 jar 启动示例:
bash
nohup java -Xms512m -Xmx512m -Xss256k -XX:+UseG1GC -jar app.jar --spring.profiles.active=prod &
参数一定要放在 -jar 前面,-jar 后面通常是应用参数,不再是 JVM 参数。
常见 JVM 调优参数
JVM 参数很多,但面试和日常排障最常用的是这几类:
| 参数 | 作用 |
|---|---|
-Xms |
初始堆大小 |
-Xmx |
最大堆大小 |
-Xss |
每个线程的栈大小 |
-XX:MetaspaceSize |
元空间初始触发 GC 阈值 |
-XX:MaxMetaspaceSize |
元空间最大值 |
-XX:MaxDirectMemorySize |
直接内存最大值 |
-XX:+UseG1GC |
使用 G1 垃圾回收器 |
-XX:MaxGCPauseMillis |
G1 停顿时间目标 |
-XX:+HeapDumpOnOutOfMemoryError |
OOM 时自动生成堆转储 |
-XX:HeapDumpPath |
指定堆转储文件路径 |
堆大小通常建议 -Xms 和 -Xmx 设置成相同值,减少运行时堆扩缩容带来的额外开销。
bash
java -Xms2g -Xmx2g -jar app.jar
但堆不是越大越好。堆太小,GC 频繁;堆太大,单次回收可能更慢。合理值要结合对象分配速度、存活对象大小、机器内存和容器限制一起看。
容器环境不要只看 Xmx
现在很多 Java 服务跑在 Docker 或 Kubernetes 里,内存限制来自容器,而不是整台宿主机。这个场景下,-Xmx 不是 Java 进程的全部内存。
一个 Java 进程的内存大致可以这样看:
#mermaid-svg-jv93Ct0bvwGIoTGH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jv93Ct0bvwGIoTGH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jv93Ct0bvwGIoTGH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jv93Ct0bvwGIoTGH .error-icon{fill:#552222;}#mermaid-svg-jv93Ct0bvwGIoTGH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jv93Ct0bvwGIoTGH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jv93Ct0bvwGIoTGH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jv93Ct0bvwGIoTGH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jv93Ct0bvwGIoTGH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jv93Ct0bvwGIoTGH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jv93Ct0bvwGIoTGH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jv93Ct0bvwGIoTGH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jv93Ct0bvwGIoTGH .marker.cross{stroke:#333333;}#mermaid-svg-jv93Ct0bvwGIoTGH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jv93Ct0bvwGIoTGH p{margin:0;}#mermaid-svg-jv93Ct0bvwGIoTGH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jv93Ct0bvwGIoTGH .cluster-label text{fill:#333;}#mermaid-svg-jv93Ct0bvwGIoTGH .cluster-label span{color:#333;}#mermaid-svg-jv93Ct0bvwGIoTGH .cluster-label span p{background-color:transparent;}#mermaid-svg-jv93Ct0bvwGIoTGH .label text,#mermaid-svg-jv93Ct0bvwGIoTGH span{fill:#333;color:#333;}#mermaid-svg-jv93Ct0bvwGIoTGH .node rect,#mermaid-svg-jv93Ct0bvwGIoTGH .node circle,#mermaid-svg-jv93Ct0bvwGIoTGH .node ellipse,#mermaid-svg-jv93Ct0bvwGIoTGH .node polygon,#mermaid-svg-jv93Ct0bvwGIoTGH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jv93Ct0bvwGIoTGH .rough-node .label text,#mermaid-svg-jv93Ct0bvwGIoTGH .node .label text,#mermaid-svg-jv93Ct0bvwGIoTGH .image-shape .label,#mermaid-svg-jv93Ct0bvwGIoTGH .icon-shape .label{text-anchor:middle;}#mermaid-svg-jv93Ct0bvwGIoTGH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jv93Ct0bvwGIoTGH .rough-node .label,#mermaid-svg-jv93Ct0bvwGIoTGH .node .label,#mermaid-svg-jv93Ct0bvwGIoTGH .image-shape .label,#mermaid-svg-jv93Ct0bvwGIoTGH .icon-shape .label{text-align:center;}#mermaid-svg-jv93Ct0bvwGIoTGH .node.clickable{cursor:pointer;}#mermaid-svg-jv93Ct0bvwGIoTGH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jv93Ct0bvwGIoTGH .arrowheadPath{fill:#333333;}#mermaid-svg-jv93Ct0bvwGIoTGH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jv93Ct0bvwGIoTGH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jv93Ct0bvwGIoTGH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jv93Ct0bvwGIoTGH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jv93Ct0bvwGIoTGH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jv93Ct0bvwGIoTGH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jv93Ct0bvwGIoTGH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jv93Ct0bvwGIoTGH .cluster text{fill:#333;}#mermaid-svg-jv93Ct0bvwGIoTGH .cluster span{color:#333;}#mermaid-svg-jv93Ct0bvwGIoTGH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jv93Ct0bvwGIoTGH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jv93Ct0bvwGIoTGH rect.text{fill:none;stroke-width:0;}#mermaid-svg-jv93Ct0bvwGIoTGH .icon-shape,#mermaid-svg-jv93Ct0bvwGIoTGH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jv93Ct0bvwGIoTGH .icon-shape p,#mermaid-svg-jv93Ct0bvwGIoTGH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jv93Ct0bvwGIoTGH .icon-shape .label rect,#mermaid-svg-jv93Ct0bvwGIoTGH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jv93Ct0bvwGIoTGH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jv93Ct0bvwGIoTGH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jv93Ct0bvwGIoTGH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 容器内存限制
Java 堆
元空间
直接内存
线程栈
代码缓存
GC 和 JVM 本地开销
其他本地内存
如果容器限制是 1g,你把 -Xmx 直接设成 1g,看起来堆空间很充足,但元空间、直接内存、线程栈、JIT 代码缓存、JVM 本地结构也都要占内存。结果可能不是 Java 自己抛 OutOfMemoryError,而是容器被系统直接杀掉,表现为 OOMKilled。
更稳的做法是给堆留出边界:
bash
java -XX:MaxRAMPercentage=70.0 -XX:+UseG1GC -jar app.jar
或者明确设置:
bash
java -Xms512m -Xmx512m -XX:MaxDirectMemorySize=128m -jar app.jar
容器里排查内存问题时,要同时看几件事:
| 观察项 | 说明 |
|---|---|
| 容器 memory limit | Java 进程真正可用的上限 |
-Xmx |
最大堆大小 |
| 线程数量 | 每个线程都有栈空间 |
| 直接内存 | NIO、Netty 常见 |
| 元空间 | 类加载和动态代理相关 |
| OOM 类型 | 区分 Java OOM 和容器 OOMKilled |
一句话:容器里调 JVM,不能只问堆多大,还要问整个 Java 进程加起来会不会超过容器限制。
GC 日志参数
不同 JDK 版本 GC 日志参数不一样。
JDK 8 常见写法:
bash
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/logs/gc.log
JDK 9 及以后推荐统一日志:
bash
-Xlog:gc*:file=/logs/gc.log:time,uptime,level,tags
GC 日志可以回答几个关键问题:
| 问题 | 观察点 |
|---|---|
| GC 是否频繁 | Young GC、Full GC 次数 |
| 停顿是否过长 | 每次 GC pause 时间 |
| 老年代是否持续上涨 | Old 区回收前后变化 |
| 是否存在内存泄漏趋势 | Full GC 后堆仍降不下来 |
| G1 Mixed GC 是否有效 | Mixed GC 后老年代是否下降 |
常用 JVM 工具
#mermaid-svg-vP6p4JOqJOZkaWaX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vP6p4JOqJOZkaWaX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vP6p4JOqJOZkaWaX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vP6p4JOqJOZkaWaX .error-icon{fill:#552222;}#mermaid-svg-vP6p4JOqJOZkaWaX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vP6p4JOqJOZkaWaX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vP6p4JOqJOZkaWaX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vP6p4JOqJOZkaWaX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vP6p4JOqJOZkaWaX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vP6p4JOqJOZkaWaX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vP6p4JOqJOZkaWaX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vP6p4JOqJOZkaWaX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vP6p4JOqJOZkaWaX .marker.cross{stroke:#333333;}#mermaid-svg-vP6p4JOqJOZkaWaX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vP6p4JOqJOZkaWaX p{margin:0;}#mermaid-svg-vP6p4JOqJOZkaWaX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vP6p4JOqJOZkaWaX .cluster-label text{fill:#333;}#mermaid-svg-vP6p4JOqJOZkaWaX .cluster-label span{color:#333;}#mermaid-svg-vP6p4JOqJOZkaWaX .cluster-label span p{background-color:transparent;}#mermaid-svg-vP6p4JOqJOZkaWaX .label text,#mermaid-svg-vP6p4JOqJOZkaWaX span{fill:#333;color:#333;}#mermaid-svg-vP6p4JOqJOZkaWaX .node rect,#mermaid-svg-vP6p4JOqJOZkaWaX .node circle,#mermaid-svg-vP6p4JOqJOZkaWaX .node ellipse,#mermaid-svg-vP6p4JOqJOZkaWaX .node polygon,#mermaid-svg-vP6p4JOqJOZkaWaX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vP6p4JOqJOZkaWaX .rough-node .label text,#mermaid-svg-vP6p4JOqJOZkaWaX .node .label text,#mermaid-svg-vP6p4JOqJOZkaWaX .image-shape .label,#mermaid-svg-vP6p4JOqJOZkaWaX .icon-shape .label{text-anchor:middle;}#mermaid-svg-vP6p4JOqJOZkaWaX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vP6p4JOqJOZkaWaX .rough-node .label,#mermaid-svg-vP6p4JOqJOZkaWaX .node .label,#mermaid-svg-vP6p4JOqJOZkaWaX .image-shape .label,#mermaid-svg-vP6p4JOqJOZkaWaX .icon-shape .label{text-align:center;}#mermaid-svg-vP6p4JOqJOZkaWaX .node.clickable{cursor:pointer;}#mermaid-svg-vP6p4JOqJOZkaWaX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vP6p4JOqJOZkaWaX .arrowheadPath{fill:#333333;}#mermaid-svg-vP6p4JOqJOZkaWaX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vP6p4JOqJOZkaWaX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vP6p4JOqJOZkaWaX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vP6p4JOqJOZkaWaX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vP6p4JOqJOZkaWaX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vP6p4JOqJOZkaWaX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vP6p4JOqJOZkaWaX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vP6p4JOqJOZkaWaX .cluster text{fill:#333;}#mermaid-svg-vP6p4JOqJOZkaWaX .cluster span{color:#333;}#mermaid-svg-vP6p4JOqJOZkaWaX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vP6p4JOqJOZkaWaX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vP6p4JOqJOZkaWaX rect.text{fill:none;stroke-width:0;}#mermaid-svg-vP6p4JOqJOZkaWaX .icon-shape,#mermaid-svg-vP6p4JOqJOZkaWaX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vP6p4JOqJOZkaWaX .icon-shape p,#mermaid-svg-vP6p4JOqJOZkaWaX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vP6p4JOqJOZkaWaX .icon-shape .label rect,#mermaid-svg-vP6p4JOqJOZkaWaX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vP6p4JOqJOZkaWaX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vP6p4JOqJOZkaWaX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vP6p4JOqJOZkaWaX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} JVM 排障工具
jps
jstat
jstack
jmap
jcmd
jconsole
VisualVM
| 工具 | 作用 |
|---|---|
jps |
查看 Java 进程 |
jstat |
查看 GC、类加载、内存统计 |
jstack |
查看线程栈,排查死锁、CPU 高、线程阻塞 |
jmap |
查看堆信息,生成 heap dump |
jcmd |
综合诊断命令,很多场景可替代部分传统工具 |
jconsole |
图形化查看内存、线程、类、MBean |
VisualVM |
图形化分析线程、堆、CPU、dump 文件 |
常用命令示例:
bash
jps -l
jstat -gcutil <pid> 1000 10
jstack <pid> > thread.txt
jmap -dump:format=b,file=heap.hprof <pid>
jcmd <pid> GC.heap_info
线上环境生成 dump 要谨慎。dump 文件可能很大,会带来磁盘和停顿风险,最好先确认磁盘空间、业务影响和应急窗口。
内存泄漏排查思路
内存泄漏常见表现是:应用运行一段时间后越来越慢,Full GC 越来越频繁,最后出现 OOM。
典型错误包括:
text
java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: Metaspace
java.lang.StackOverflowError
java.lang.OutOfMemoryError: Direct buffer memory
不同错误对应不同方向:
| 错误 | 常见原因 |
|---|---|
Java heap space |
堆对象过多或堆内存泄漏 |
Metaspace |
类加载过多、类加载器无法释放 |
StackOverflowError |
递归过深、调用链异常 |
Direct buffer memory |
直接内存使用过多或释放不及时 |
排查堆内存泄漏可以按这条流程走:
#mermaid-svg-eVjhxa8qwAQVGQ73{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eVjhxa8qwAQVGQ73 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eVjhxa8qwAQVGQ73 .error-icon{fill:#552222;}#mermaid-svg-eVjhxa8qwAQVGQ73 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eVjhxa8qwAQVGQ73 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eVjhxa8qwAQVGQ73 .marker.cross{stroke:#333333;}#mermaid-svg-eVjhxa8qwAQVGQ73 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eVjhxa8qwAQVGQ73 p{margin:0;}#mermaid-svg-eVjhxa8qwAQVGQ73 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eVjhxa8qwAQVGQ73 .cluster-label text{fill:#333;}#mermaid-svg-eVjhxa8qwAQVGQ73 .cluster-label span{color:#333;}#mermaid-svg-eVjhxa8qwAQVGQ73 .cluster-label span p{background-color:transparent;}#mermaid-svg-eVjhxa8qwAQVGQ73 .label text,#mermaid-svg-eVjhxa8qwAQVGQ73 span{fill:#333;color:#333;}#mermaid-svg-eVjhxa8qwAQVGQ73 .node rect,#mermaid-svg-eVjhxa8qwAQVGQ73 .node circle,#mermaid-svg-eVjhxa8qwAQVGQ73 .node ellipse,#mermaid-svg-eVjhxa8qwAQVGQ73 .node polygon,#mermaid-svg-eVjhxa8qwAQVGQ73 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eVjhxa8qwAQVGQ73 .rough-node .label text,#mermaid-svg-eVjhxa8qwAQVGQ73 .node .label text,#mermaid-svg-eVjhxa8qwAQVGQ73 .image-shape .label,#mermaid-svg-eVjhxa8qwAQVGQ73 .icon-shape .label{text-anchor:middle;}#mermaid-svg-eVjhxa8qwAQVGQ73 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eVjhxa8qwAQVGQ73 .rough-node .label,#mermaid-svg-eVjhxa8qwAQVGQ73 .node .label,#mermaid-svg-eVjhxa8qwAQVGQ73 .image-shape .label,#mermaid-svg-eVjhxa8qwAQVGQ73 .icon-shape .label{text-align:center;}#mermaid-svg-eVjhxa8qwAQVGQ73 .node.clickable{cursor:pointer;}#mermaid-svg-eVjhxa8qwAQVGQ73 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eVjhxa8qwAQVGQ73 .arrowheadPath{fill:#333333;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eVjhxa8qwAQVGQ73 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eVjhxa8qwAQVGQ73 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eVjhxa8qwAQVGQ73 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eVjhxa8qwAQVGQ73 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eVjhxa8qwAQVGQ73 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eVjhxa8qwAQVGQ73 .cluster text{fill:#333;}#mermaid-svg-eVjhxa8qwAQVGQ73 .cluster span{color:#333;}#mermaid-svg-eVjhxa8qwAQVGQ73 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eVjhxa8qwAQVGQ73 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eVjhxa8qwAQVGQ73 rect.text{fill:none;stroke-width:0;}#mermaid-svg-eVjhxa8qwAQVGQ73 .icon-shape,#mermaid-svg-eVjhxa8qwAQVGQ73 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eVjhxa8qwAQVGQ73 .icon-shape p,#mermaid-svg-eVjhxa8qwAQVGQ73 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eVjhxa8qwAQVGQ73 .icon-shape .label rect,#mermaid-svg-eVjhxa8qwAQVGQ73 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eVjhxa8qwAQVGQ73 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eVjhxa8qwAQVGQ73 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eVjhxa8qwAQVGQ73 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
发现内存持续上涨
查看 GC 日志和监控
Full GC 后内存是否明显下降
可能是内存压力或参数不合理
怀疑内存泄漏
生成 heap dump
使用 VisualVM 或 MAT 分析
查看大对象和引用链
定位持有对象的集合或静态引用
修复代码并验证
推荐 JVM 参数:
bash
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/app/dumps/
这样 OOM 时能自动留下现场,避免应用直接崩掉后没有分析依据。
分析 dump 时重点看:
| 观察项 | 说明 |
|---|---|
| Dominator Tree | 谁保留了最多对象 |
| Retained Size | 释放某对象后可释放的总内存 |
| GC Roots Path | 对象为什么仍然可达 |
| 大集合 | 是否存在无限增长的 List、Map、缓存 |
| 重复对象 | 是否有大量相同字符串、DTO、数组 |
修复方向通常不是"把堆调大"这么简单。堆调大只能延迟爆炸,如果引用链还在,最终还是会 OOM。
CPU 飙高排查思路
CPU 飙高常见原因包括死循环、频繁 GC、锁竞争、自旋、复杂计算、线程池过载。
排查 Java 进程 CPU 高,可以按这条链路走:
#mermaid-svg-RSebNKizKj8nD1jM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RSebNKizKj8nD1jM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RSebNKizKj8nD1jM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RSebNKizKj8nD1jM .error-icon{fill:#552222;}#mermaid-svg-RSebNKizKj8nD1jM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RSebNKizKj8nD1jM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RSebNKizKj8nD1jM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RSebNKizKj8nD1jM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RSebNKizKj8nD1jM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RSebNKizKj8nD1jM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RSebNKizKj8nD1jM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RSebNKizKj8nD1jM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RSebNKizKj8nD1jM .marker.cross{stroke:#333333;}#mermaid-svg-RSebNKizKj8nD1jM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RSebNKizKj8nD1jM p{margin:0;}#mermaid-svg-RSebNKizKj8nD1jM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RSebNKizKj8nD1jM .cluster-label text{fill:#333;}#mermaid-svg-RSebNKizKj8nD1jM .cluster-label span{color:#333;}#mermaid-svg-RSebNKizKj8nD1jM .cluster-label span p{background-color:transparent;}#mermaid-svg-RSebNKizKj8nD1jM .label text,#mermaid-svg-RSebNKizKj8nD1jM span{fill:#333;color:#333;}#mermaid-svg-RSebNKizKj8nD1jM .node rect,#mermaid-svg-RSebNKizKj8nD1jM .node circle,#mermaid-svg-RSebNKizKj8nD1jM .node ellipse,#mermaid-svg-RSebNKizKj8nD1jM .node polygon,#mermaid-svg-RSebNKizKj8nD1jM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RSebNKizKj8nD1jM .rough-node .label text,#mermaid-svg-RSebNKizKj8nD1jM .node .label text,#mermaid-svg-RSebNKizKj8nD1jM .image-shape .label,#mermaid-svg-RSebNKizKj8nD1jM .icon-shape .label{text-anchor:middle;}#mermaid-svg-RSebNKizKj8nD1jM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RSebNKizKj8nD1jM .rough-node .label,#mermaid-svg-RSebNKizKj8nD1jM .node .label,#mermaid-svg-RSebNKizKj8nD1jM .image-shape .label,#mermaid-svg-RSebNKizKj8nD1jM .icon-shape .label{text-align:center;}#mermaid-svg-RSebNKizKj8nD1jM .node.clickable{cursor:pointer;}#mermaid-svg-RSebNKizKj8nD1jM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RSebNKizKj8nD1jM .arrowheadPath{fill:#333333;}#mermaid-svg-RSebNKizKj8nD1jM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RSebNKizKj8nD1jM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RSebNKizKj8nD1jM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RSebNKizKj8nD1jM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RSebNKizKj8nD1jM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RSebNKizKj8nD1jM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RSebNKizKj8nD1jM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RSebNKizKj8nD1jM .cluster text{fill:#333;}#mermaid-svg-RSebNKizKj8nD1jM .cluster span{color:#333;}#mermaid-svg-RSebNKizKj8nD1jM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RSebNKizKj8nD1jM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RSebNKizKj8nD1jM rect.text{fill:none;stroke-width:0;}#mermaid-svg-RSebNKizKj8nD1jM .icon-shape,#mermaid-svg-RSebNKizKj8nD1jM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RSebNKizKj8nD1jM .icon-shape p,#mermaid-svg-RSebNKizKj8nD1jM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RSebNKizKj8nD1jM .icon-shape .label rect,#mermaid-svg-RSebNKizKj8nD1jM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RSebNKizKj8nD1jM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RSebNKizKj8nD1jM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RSebNKizKj8nD1jM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 发现 CPU 飙高
top 找到高 CPU 进程
ps 找到进程内高 CPU 线程
线程 id 转十六进制
jstack 导出线程栈
按 nid 搜索对应线程
定位代码方法和行号
判断死循环、锁竞争或频繁 GC
常用命令:
bash
top
ps H -eo pid,tid,%cpu | grep <pid>
printf "%x\n" <tid>
jstack <pid> > thread.txt
jstack 中线程的 nid 通常是十六进制,所以需要把操作系统线程 ID 转成十六进制再搜索。
如果线程栈一直停在同一段业务代码,可能是死循环或复杂计算。如果大量线程处于 BLOCKED,可能是锁竞争。如果 CPU 高同时 GC 日志疯狂刷,可能是频繁 GC 导致。
#mermaid-svg-p6D6TGATfz2eZX4A{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-p6D6TGATfz2eZX4A .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-p6D6TGATfz2eZX4A .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-p6D6TGATfz2eZX4A .error-icon{fill:#552222;}#mermaid-svg-p6D6TGATfz2eZX4A .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-p6D6TGATfz2eZX4A .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-p6D6TGATfz2eZX4A .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-p6D6TGATfz2eZX4A .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-p6D6TGATfz2eZX4A .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-p6D6TGATfz2eZX4A .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-p6D6TGATfz2eZX4A .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-p6D6TGATfz2eZX4A .marker{fill:#333333;stroke:#333333;}#mermaid-svg-p6D6TGATfz2eZX4A .marker.cross{stroke:#333333;}#mermaid-svg-p6D6TGATfz2eZX4A svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-p6D6TGATfz2eZX4A p{margin:0;}#mermaid-svg-p6D6TGATfz2eZX4A .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-p6D6TGATfz2eZX4A .cluster-label text{fill:#333;}#mermaid-svg-p6D6TGATfz2eZX4A .cluster-label span{color:#333;}#mermaid-svg-p6D6TGATfz2eZX4A .cluster-label span p{background-color:transparent;}#mermaid-svg-p6D6TGATfz2eZX4A .label text,#mermaid-svg-p6D6TGATfz2eZX4A span{fill:#333;color:#333;}#mermaid-svg-p6D6TGATfz2eZX4A .node rect,#mermaid-svg-p6D6TGATfz2eZX4A .node circle,#mermaid-svg-p6D6TGATfz2eZX4A .node ellipse,#mermaid-svg-p6D6TGATfz2eZX4A .node polygon,#mermaid-svg-p6D6TGATfz2eZX4A .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-p6D6TGATfz2eZX4A .rough-node .label text,#mermaid-svg-p6D6TGATfz2eZX4A .node .label text,#mermaid-svg-p6D6TGATfz2eZX4A .image-shape .label,#mermaid-svg-p6D6TGATfz2eZX4A .icon-shape .label{text-anchor:middle;}#mermaid-svg-p6D6TGATfz2eZX4A .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-p6D6TGATfz2eZX4A .rough-node .label,#mermaid-svg-p6D6TGATfz2eZX4A .node .label,#mermaid-svg-p6D6TGATfz2eZX4A .image-shape .label,#mermaid-svg-p6D6TGATfz2eZX4A .icon-shape .label{text-align:center;}#mermaid-svg-p6D6TGATfz2eZX4A .node.clickable{cursor:pointer;}#mermaid-svg-p6D6TGATfz2eZX4A .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-p6D6TGATfz2eZX4A .arrowheadPath{fill:#333333;}#mermaid-svg-p6D6TGATfz2eZX4A .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-p6D6TGATfz2eZX4A .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-p6D6TGATfz2eZX4A .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p6D6TGATfz2eZX4A .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-p6D6TGATfz2eZX4A .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p6D6TGATfz2eZX4A .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-p6D6TGATfz2eZX4A .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-p6D6TGATfz2eZX4A .cluster text{fill:#333;}#mermaid-svg-p6D6TGATfz2eZX4A .cluster span{color:#333;}#mermaid-svg-p6D6TGATfz2eZX4A div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-p6D6TGATfz2eZX4A .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-p6D6TGATfz2eZX4A rect.text{fill:none;stroke-width:0;}#mermaid-svg-p6D6TGATfz2eZX4A .icon-shape,#mermaid-svg-p6D6TGATfz2eZX4A .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p6D6TGATfz2eZX4A .icon-shape p,#mermaid-svg-p6D6TGATfz2eZX4A .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-p6D6TGATfz2eZX4A .icon-shape .label rect,#mermaid-svg-p6D6TGATfz2eZX4A .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p6D6TGATfz2eZX4A .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-p6D6TGATfz2eZX4A .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-p6D6TGATfz2eZX4A :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 业务循环代码
锁相关调用
GC 线程活跃
线程池任务
高 CPU 线程栈
栈顶是什么
检查死循环或算法复杂度
检查锁竞争
检查内存压力和 GC 日志
检查任务积压和线程池参数
调优的正确顺序
很多 JVM 问题不是参数问题,而是代码、流量、对象生命周期或资源释放问题。
一个更稳的调优顺序是:
#mermaid-svg-FqTQlD2Wh4srUFlu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FqTQlD2Wh4srUFlu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FqTQlD2Wh4srUFlu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FqTQlD2Wh4srUFlu .error-icon{fill:#552222;}#mermaid-svg-FqTQlD2Wh4srUFlu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FqTQlD2Wh4srUFlu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FqTQlD2Wh4srUFlu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FqTQlD2Wh4srUFlu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FqTQlD2Wh4srUFlu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FqTQlD2Wh4srUFlu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FqTQlD2Wh4srUFlu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FqTQlD2Wh4srUFlu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FqTQlD2Wh4srUFlu .marker.cross{stroke:#333333;}#mermaid-svg-FqTQlD2Wh4srUFlu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FqTQlD2Wh4srUFlu p{margin:0;}#mermaid-svg-FqTQlD2Wh4srUFlu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FqTQlD2Wh4srUFlu .cluster-label text{fill:#333;}#mermaid-svg-FqTQlD2Wh4srUFlu .cluster-label span{color:#333;}#mermaid-svg-FqTQlD2Wh4srUFlu .cluster-label span p{background-color:transparent;}#mermaid-svg-FqTQlD2Wh4srUFlu .label text,#mermaid-svg-FqTQlD2Wh4srUFlu span{fill:#333;color:#333;}#mermaid-svg-FqTQlD2Wh4srUFlu .node rect,#mermaid-svg-FqTQlD2Wh4srUFlu .node circle,#mermaid-svg-FqTQlD2Wh4srUFlu .node ellipse,#mermaid-svg-FqTQlD2Wh4srUFlu .node polygon,#mermaid-svg-FqTQlD2Wh4srUFlu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FqTQlD2Wh4srUFlu .rough-node .label text,#mermaid-svg-FqTQlD2Wh4srUFlu .node .label text,#mermaid-svg-FqTQlD2Wh4srUFlu .image-shape .label,#mermaid-svg-FqTQlD2Wh4srUFlu .icon-shape .label{text-anchor:middle;}#mermaid-svg-FqTQlD2Wh4srUFlu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FqTQlD2Wh4srUFlu .rough-node .label,#mermaid-svg-FqTQlD2Wh4srUFlu .node .label,#mermaid-svg-FqTQlD2Wh4srUFlu .image-shape .label,#mermaid-svg-FqTQlD2Wh4srUFlu .icon-shape .label{text-align:center;}#mermaid-svg-FqTQlD2Wh4srUFlu .node.clickable{cursor:pointer;}#mermaid-svg-FqTQlD2Wh4srUFlu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FqTQlD2Wh4srUFlu .arrowheadPath{fill:#333333;}#mermaid-svg-FqTQlD2Wh4srUFlu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FqTQlD2Wh4srUFlu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FqTQlD2Wh4srUFlu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FqTQlD2Wh4srUFlu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FqTQlD2Wh4srUFlu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FqTQlD2Wh4srUFlu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FqTQlD2Wh4srUFlu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FqTQlD2Wh4srUFlu .cluster text{fill:#333;}#mermaid-svg-FqTQlD2Wh4srUFlu .cluster span{color:#333;}#mermaid-svg-FqTQlD2Wh4srUFlu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FqTQlD2Wh4srUFlu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FqTQlD2Wh4srUFlu rect.text{fill:none;stroke-width:0;}#mermaid-svg-FqTQlD2Wh4srUFlu .icon-shape,#mermaid-svg-FqTQlD2Wh4srUFlu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FqTQlD2Wh4srUFlu .icon-shape p,#mermaid-svg-FqTQlD2Wh4srUFlu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FqTQlD2Wh4srUFlu .icon-shape .label rect,#mermaid-svg-FqTQlD2Wh4srUFlu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FqTQlD2Wh4srUFlu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FqTQlD2Wh4srUFlu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FqTQlD2Wh4srUFlu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 内存
CPU
线程
IO
确认现象
采集监控和日志
定位瓶颈类型
瓶颈在哪里
分析 GC 和 dump
分析线程栈
分析阻塞和线程池
分析外部依赖和系统调用
修改代码或参数
压测或灰度验证
如果没有证据,不要直接改 -Xmx、换 GC 或调线程池。参数调整必须服务于具体问题。
常见调优建议
| 场景 | 建议 |
|---|---|
| Young GC 过于频繁 | 观察对象分配速率,适当调整堆或新生代比例 |
| Full GC 频繁 | 检查老年代增长、内存泄漏、大对象、元空间 |
| GC 停顿过长 | 分析 GC 日志,考虑 G1 参数、堆大小、对象存活率 |
| 线程数过多 | 检查线程池、-Xss、阻塞调用 |
| Metaspace OOM | 检查动态类生成、类加载器泄漏、热部署 |
| Direct Memory OOM | 检查 NIO、Netty、直接缓冲区释放 |
调优的底层逻辑是:减少无效对象分配,缩短对象生命周期,降低老年代压力,控制线程数量,让 GC 做更少的无用功。
面试回答模板
可以这样回答:
JVM 调优我会先看现象和监控,而不是直接改参数。如果是内存问题,先看 GC 日志,判断 Young GC、Full GC 是否频繁,以及 Full GC 后内存是否能降下来。如果降不下来,就怀疑内存泄漏,通过
jmap或 OOM 参数生成 heap dump,再用 VisualVM 或 MAT 看大对象、引用链和 GC Roots。如果是 CPU 飙高,先用top找进程,再用ps H找高 CPU 线程,把线程 ID 转成十六进制后到jstack里查nid,定位具体线程栈,判断是死循环、锁竞争、频繁 GC 还是线程池任务过载。参数上常见会关注-Xms、-Xmx、-Xss、元空间、直接内存、GC 收集器和 GC 日志。调优后要压测或灰度验证,不能只凭感觉改。
小结
JVM 调优的关键不是参数清单,而是排查闭环:
看现象,拿证据,定位内存、GC、线程或 CPU,再决定是改代码、改架构还是改 JVM 参数。
没有证据的调优,只是在碰运气。