惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
月光博客
月光博客
AI
AI
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
CXSECURITY Database RSS Feed - CXSecurity.com
WordPress大学
WordPress大学
GbyAI
GbyAI
L
Lohrmann on Cybersecurity
O
OpenAI News
Schneier on Security
Schneier on Security
P
Palo Alto Networks Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Troy Hunt's Blog
V2EX - 技术
V2EX - 技术
W
WeLiveSecurity
L
LINUX DO - 最新话题
人人都是产品经理
人人都是产品经理
S
Security Affairs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
A
Arctic Wolf
Recorded Future
Recorded Future
Microsoft Security Blog
Microsoft Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
GRAHAM CLULEY
N
Netflix TechBlog - Medium
TaoSecurity Blog
TaoSecurity Blog
C
Check Point Blog
Scott Helme
Scott Helme
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Apple Machine Learning Research
Apple Machine Learning Research
PCI Perspectives
PCI Perspectives
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Vercel News
Vercel News
The Hacker News
The Hacker News
Y
Y Combinator Blog
Latest news
Latest news
SecWiki News
SecWiki News
Hugging Face - Blog
Hugging Face - Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Webroot Blog
Webroot Blog
Google DeepMind News
Google DeepMind News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
C
Cisco Blogs
博客园_首页
H
Hackread – Cybersecurity News, Data Breaches, AI and More
宝玉的分享
宝玉的分享
L
LINUX DO - 热门话题

博客园 - 郭慕荣

彻底搞懂 Codex Skill 与插件:区别、试用、核心作用、项目落地全指南(程序员实战向) Codex Skill 和插件到底有什么区别?程序员如何在项目中落地使用 claudecode 配置防止配置文件泄露总结 Claude code分析外部文件总结 Claude code三种模式详解 hasCompletedOnboarding详解 Claudecode 有哪些常用的命令 claude.md文件详解 claude code 的setting文件详解 Docker部署zookeeper总结 Mac中git ssh的配置(GitLab) Java 类加载机制 面试题(一) jvm常用的参数有哪些? 怎么配置? hashmap 和currenthashmap 的原理?详解一下 aop在项目中使用的场景?怎么使用? Java dubbo spring springboot中的spi机制 spring中常见的两种代理模式 Redis的zset 面试汇总 drools 规则引擎在线化配置 springcloud中常用的注解详解 springcloud中网关gateway总结 spring是怎么解决循环依赖的? MySQL 死锁 怎么处理? 在写left join的时候 是大表在左侧 还是小表在左侧(二) 在写left join的时候 是大表在左侧 还是小表在左侧(一) nacos客户端(接口调用者)如何感知被调用服务下线? (二) nacos客户端(接口调用者)如何感知被调用服务下线?(一) 在MySQL中 redolog undolog binlog 写入的场景,顺序
如何监控和调优JVM性能?
郭慕荣 · 2025-10-29 · via 博客园 - 郭慕荣

JVM 性能监控与调优是保障 Java 应用稳定运行的核心环节,目标是减少内存溢出(OOM)风险、降低 GC 停顿时间、提高资源利用率(CPU / 内存)。整个过程需遵循 “监控指标→定位瓶颈→调整参数→验证效果” 的闭环,具体步骤和工具如下:

监控是调优的前提,需通过工具实时或离线采集关键指标,识别性能瓶颈(如内存泄漏、GC 频繁、线程阻塞等)。

按使用场景分为命令行工具(轻量、适合服务器环境)、可视化工具(直观、适合问题分析)、APM 工具(全链路监控、适合生产环境)。

  • jps:查看 Java 进程 ID(基础工具,用于定位目标进程)

    jps -l  # 显示进程ID和主类全路径(如 12345 com.example.Application)
    
  • jstat:监控 JVM 内存和 GC 状态(最常用的实时监控工具)

    # 格式:jstat -<选项> <进程ID> <间隔时间(ms)> <次数>
    jstat -gc 12345 1000 10  

    关键指标(以-gc为例):

    • S0C/S1C:Survivor 区总容量;S0U/S1U:Survivor 区已使用容量
    • EC/EU:Eden 区总容量 / 已使用容量
    • OC/OU:老年代总容量 / 已使用容量
    • MC/MU:元空间总容量 / 已使用容量
    • YGC/YGCT:新生代 GC 次数 / 总耗时(秒)
    • FGC/FGCT:Full GC 次数 / 总耗时(秒)
    • GCT:GC 总耗时(秒)
  • jmap:生成堆快照(.hprof)或查看堆内存分布(用于分析内存泄漏、大对象)

    jmap -heap 12345  # 查看堆内存配置和使用情况(如各区域大小、GC收集器)
    jmap -dump:format=b,file=heap.hprof 12345  
  • jstack:查看线程栈信息(用于分析线程阻塞、死锁、CPU 过高)

    jstack 12345 > thread.log  # 导出线程栈到文件
    # 结合top命令定位高CPU线程:top -Hp 12345 找到高CPU线程ID(十进制),转为十六进制在thread.log中搜索
    

    关键信息:线程状态(RUNNABLE/BLOCKED/WAITING)、锁信息(如synchronized阻塞的锁对象)。

  • jinfo:查看或修改 JVM 参数(动态调整部分参数,如 GC 日志开关)

    jinfo -flags 12345  # 查看当前JVM所有参数(如-Xms、-XX:UseG1GC等)
    jinfo -sysprops 12345  
  • JConsole:JDK 自带的简易监控工具(jconsole命令启动),支持监控:

    • 内存(堆 / 非堆实时使用趋势)、线程(状态、栈信息)、GC(次数 / 耗时)、MBean(JVM 内部管理接口)。
  • VisualVM:功能更全面的可视化工具(需单独下载VisualVM),支持:

    • 生成 / 导入堆快照、线程快照,内置分析器(内存 / CPU 分析);
    • 插件扩展(如 GC 日志分析、Visual GC 插件可视化 GC 过程)。
  • MAT(Memory Analyzer Tool):专注堆快照分析(下载地址),用于定位内存泄漏:

    • 自动检测内存泄漏疑点(“Leak Suspects” 报告);
    • 分析对象引用链(“Dominator Tree” 查看大对象的引用关系);
    • 计算对象 retained size(被该对象直接 / 间接引用的总内存)。
  • GCEasy:在线 GC 日志分析工具(官网),上传 GC 日志后生成可视化报告:

    • GC 频率、停顿时间分布、内存增长趋势;
    • 自动诊断问题(如 “Full GC 过于频繁”“新生代过小”)。

适合分布式系统,结合业务指标监控 JVM 性能,如:

  • Prometheus + Grafana:通过jmx_exporter暴露 JVM 指标(如堆内存、GC 次数),Grafana 可视化监控面板,支持告警(如 GC 停顿超阈值)。
  • SkyWalking:全链路追踪工具,内置 JVM 监控模块(内存、GC、线程、CPU),可关联业务调用链定位性能瓶颈(如某接口调用导致 GC 频繁)。
  • Elastic Stack:通过Metricbeat采集 JVM 指标,Elasticsearch存储,Kibana可视化,适合大规模集群监控。
  • 内存指标:

    • 堆内存:Eden 区使用率(持续接近 100% 可能导致 YGC 频繁)、老年代增长率(过快可能导致提前 Full GC)、Survivor 区是否被充分利用(过小可能导致对象提前进入老年代)。
    • 元空间:是否持续增长(如频繁动态生成类可能导致元空间 OOM)。
    • 直接内存:NIO 应用需关注(如 Netty,默认与堆最大值一致,溢出会抛OutOfMemoryError: Direct buffer memory)。
  • GC 指标:

    • 频率:YGC 次数(如每秒 > 1 次可能过频)、Full GC 次数(正常应很少,如每小时 > 1 次需警惕)。
    • 耗时:YGC 单次耗时(如 > 100ms 影响响应)、Full GC 单次耗时(如 > 1s 可能导致应用卡顿)。
    • 停顿率:GC 总耗时 / 应用运行总时间(吞吐量优先应用需 < 5%,低延迟应用需 < 1%)。
  • 线程指标:

    • 线程总数:是否持续增长(可能存在线程泄漏,如线程池未关闭)。
    • 阻塞 / 等待线程数:BLOCKED线程过多(锁竞争激烈)、WAITING线程过多(如线程池队列满导致线程等待)。
    • 死锁:jstack 可检测到死锁线程(需立即处理,避免资源耗尽)。
  • CPU 与负载:

    • JVM 进程 CPU 占比:过高(如 > 80%)可能是代码效率低(如死循环、频繁 GC)。
    • 系统负载:与 CPU 核心数匹配(如 4 核 CPU,负载长期 > 4 说明系统繁忙)。

调优需基于监控数据定位瓶颈,而非盲目调整参数。核心步骤:明确目标→采集数据→分析瓶颈→调整参数→验证效果。

  • 吞吐量优先:批处理任务(如数据分析),优先保证单位时间内完成更多任务,允许偶尔长 GC 停顿(如 Parallel GC)。
  • 低延迟优先:Web 应用、实时服务,优先减少响应时间波动,GC 停顿需控制在毫秒级(如 G1、ZGC)。
  • 内存高效:资源受限环境(如容器),需平衡内存占用和性能(避免过度分配内存)。

现象:老年代内存持续增长,Full GC 后内存不下降,最终 OOM;jmap -histo:live 显示某类实例数异常多。排查:

  1. 生成堆快照(jmap -dump或 OOM 自动生成);
  2. 用 MAT 分析:查看 “Dominator Tree”,找到占用内存最大的对象,通过 “Path to GC Roots” 分析引用链(为何未被回收)。 调优方案:
  • 修复代码:释放无用引用(如静态集合未清理、缓存未设置过期时间);
  • 临时缓解:增大堆内存(-Xmx),但需结合代码修复(否则只是推迟 OOM)。

现象:jstat 显示 YGC 每秒多次,或 Full GC 每几分钟一次,GC 总耗时占比高(>10%)。排查:

  • YGC 频繁:通常是新生代过小,或对象创建速度快(如大量临时对象)。
  • Full GC 频繁:老年代增长快(如大对象直接进入老年代、Survivor 区不足导致对象提前晋升)。 调优方案:
  • 调整新生代大小:增大-Xmn(如从 1G 增至 2G),减少 YGC 次数;
  • 调整 Survivor 区比例:-XX:SurvivorRatio=6(Eden:S0:S1=6:1:1,增大 Survivor 区,减少对象提前进入老年代);
  • 控制大对象:设置-XX:PretenureSizeThreshold=1048576(1MB 以上大对象直接进入老年代,避免新生代频繁 GC);
  • 更换 GC 收集器:如从 Parallel GC 换为 G1,通过-XX:MaxGCPauseMillis=100控制停顿时间。

现象:单次 GC 停顿 > 1s(如 Full GC 耗时 5s),导致应用响应超时(如 Web 请求超时)。排查:

  • 老年代过大:Full GC 需扫描整个老年代,耗时随内存增大而增加;
  • GC 收集器不合适:如 Serial GC(单线程回收)在大堆场景下停顿长。 调优方案:
  • 拆分大堆:若堆内存 > 16GB,考虑用 G1(区域化回收,只处理部分区域)或 ZGC(并发回收,停顿 < 10ms);
  • 调整 G1 参数:-XX:G1HeapRegionSize=8m(增大区域大小,减少区域数量)、-XX:InitiatingHeapOccupancyPercent=40(提前触发混合回收,避免老年代占比过高);
  • 减少老年代对象:优化代码,避免创建长生命周期大对象(如缓存对象序列化存储)。

现象:应用响应慢,jstack 显示大量BLOCKED线程,或存在死锁(Found one Java-level deadlock)。排查:

  • 死锁:jstack 日志中搜索 “deadlock”,查看相互持有锁的线程和锁对象;
  • 锁竞争:BLOCKED线程等待的锁对象被少数线程长期持有(如synchronized修饰的慢方法)。 调优方案:
  • 解决死锁:调整锁获取顺序(如统一按对象哈希值顺序获取锁);
  • 减少锁竞争:
    • 缩小锁范围(只锁必要代码块,而非整个方法);
    • 用更高效的锁(如ReentrantLock替代synchronized,支持公平锁 / 尝试获取);
    • 无锁化设计(如用Atomic类、ConcurrentHashMap 替代同步容器)。

现象:元空间内存持续增长,jstat -gc显示MU接近MC,最终 OOM。原因:频繁动态生成类(如 CGLib 代理、反射生成类),且类未被卸载(类加载器未回收)。调优方案:

  • 增大元空间上限:-XX:MaxMetaspaceSize=512m(临时缓解);
  • 优化类生成:复用代理类(如 Spring AOP 设置proxyTargetClass=true减少动态类)、避免频繁创建类加载器。
  1. 不过早调优:先保证功能正确,性能问题明确后再调优(多数性能问题源于代码,而非 JVM 参数)。
  2. 基于数据调优:所有调整必须有监控数据支撑(如 “调大 - Xmn 后 YGC 次数从 5 次 / 秒降至 1 次 / 秒”),避免凭感觉改参数。
  3. 小步迭代:每次只调整 1-2 个参数,对比前后指标变化(如先调新生代大小,再调 GC 收集器)。
  4. 结合业务场景:Web 应用优先保证低延迟(用 G1/ZGC),批处理优先保证吞吐量(用 Parallel GC)。
  5. 长期监控:调优后需持续监控(如 24 小时),确认效果稳定(避免短期优化导致长期问题)。

JVM 性能监控的核心是通过工具(jstat、MAT、APM)采集内存、GC、线程指标;调优则需针对具体瓶颈(内存泄漏、GC 频繁、线程阻塞),结合业务目标调整参数或优化代码。关键是形成 “监控→分析→调整→验证” 的闭环,而非依赖经验主义。