JVM 调优与线上排障:参数工具内存泄漏和CPU飙高

JVM 调优不是上来就改参数。真正可靠的顺序是:先确认问题,再拿到证据,再分析原因,最后小步调整并验证效果。

一句话概括:JVM 调优的核心不是背参数,而是围绕内存、GC、线程和 CPU 建立排查闭环。

JVM 参数可以在哪里设置

不同部署方式设置位置不同。

部署方式 常见设置位置
直接运行 jar java 启动命令后添加 JVM 参数
Shell 脚本启动 启动脚本中的 JAVA_OPTS 或命令行
Tomcat 部署 war catalina.shsetenv.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 对象为什么仍然可达
大集合 是否存在无限增长的 ListMap、缓存
重复对象 是否有大量相同字符串、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 参数。

没有证据的调优,只是在碰运气。

相关推荐
cfm_29142 小时前
JVM类加载机制初步了解
java·jvm
周末也要写八哥3 小时前
线程的生命周期之“守护“线程
java·开发语言·jvm
未若君雅裁21 小时前
JVM 运行时数据区:程序计数器、堆、虚拟机栈与栈帧
java·jvm
killerbasd1 天前
总结 6.9
jvm
IT龟苓膏1 天前
Java 并发基础:进程、线程、线程状态、synchronized、volatile 一篇讲清
java·开发语言·jvm
周末也要写八哥1 天前
线程的生命周期之线程睡眠
java·开发语言·jvm
瓦特what?1 天前
位运算核心技巧与应用
java·jvm·算法
程序员二叉1 天前
【JVM】类加载全过程&双亲委派机制深度解析
java·jvm·面试
cfm_29141 天前
JVM 深度入门:Class文件结构 + 字节码指令详解
jvm