ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JVM调优秘籍:从入门到拯救系统!

JVM调优秘籍:从入门到拯救系统! 全文目录开篇语前言从懵懂少年到“JVM老中医”的进化之路一、 JVM 调优的核心目标不就是“更快更稳”吗二、 常用的 JVM 内存参数“我的地盘我做主”1. 堆内存大小-Xms 和 -Xmx2. 新生代大小-Xmn 或 -XX:NewRatio3. Survivor 区大小-XX:SurvivorRatio三、 GC 收集器参数谁才是你的“垃圾处理厂”1. 经典组合JDK 8-XX:UseParallelGC 或 -XX:UseConcMarkSweepGC2. 现代选择JDK 9 默认-XX:UseG1GC3. 未来的黑科技JDK 11-XX:UseZGC 或 -XX:UseShenandoahGC四、 杂项参数与实用工具“侦探”与“旁观者”1. GC 日志-Xlog:gc* 或 -XX:PrintGCDetails 等2. 堆溢出诊断-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/path/to/dump3. JIT 编译诊断-XX:PrintCompilation -XX:UnlockDiagnosticVMOptions -XX:PrintInlining五、 JVM 参数调优的“金科玉律”我的血泪总结六、 写在最后 JVM 调优是一场没有终点的修行文末开篇语哈喽各位小伙伴们你们好呀我是喵手。运营社区C站/掘金/腾讯云/阿里云/华为云/51CTO欢迎大家常来逛逛今天我要给大家分享一些自己日常学习到的一些知识点并以文字的形式跟大家一起交流互相学习一个人虽可以走的更快但一群人可以走的更远。我是一名后端开发爱好者工作日常接触到最多的就是Java语言啦所以我都尽量抽业余时间把自己所学到所会的通过文章的形式进行输出希望以这种方式帮助到更多的初学者或者想入门的小伙伴们同时也能对自己的技术进行沉淀加以复盘查缺补漏。小伙伴们在批阅的过程中如果觉得文章不错欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持前言从懵懂少年到“JVM老中医”的进化之路想当年我还是个初出茅庐的小菜鸟写完业务代码就觉得万事大吉。哪知道一上线服务器内存报警、CPU飙升、请求超时……一问大佬大佬轻描淡写一句“你是不是没调 JVM 参数啊” 我当时心里 OSJVM 参数是啥能吃吗‍♂️从那时候起我就开始了一段“JVM 参数调优”的血泪史。从最开始的照抄网上配置到后来的逐渐理解每个参数的意义再到如今能在凌晨三点淡定地分析jstack和gc log然后敲下那几个关键参数拯救整个系统于水火之中。这经历真是比看《甄嬛传》还跌宕起伏今天我就把我那些“祖传秘方”和“翻车教训”毫无保留地分享给你。咱们不光讲参数更要讲怎么思考怎么在千变万化的业务场景中找到最适合你的那套“武功秘籍”一、 JVM 调优的核心目标不就是“更快更稳”吗说白了JVM 调优的终极目标就两个降低延迟Low Latency减少 GC 停顿时间让你的服务响应更快用户体验更好。比如电商抢购、金融交易差个几百毫秒可能就是几百万的损失。提升吞吐量High Throughput在单位时间内处理更多的请求让你的服务器能抗住更大的并发量。比如大数据批处理、日志分析追求的是每秒处理多少条数据。这两个目标往往是矛盾的就像鱼和熊掌不可兼得。你需要根据你的业务场景在这两者之间找到一个最佳平衡点。二、 常用的 JVM 内存参数“我的地盘我做主”内存参数是 JVM 调优的基石就像你建房子得先规划地基。1. 堆内存大小-Xms和-Xmx*-XmssizeJVM 启动时分配的初始堆内存。*-XmxsizeJVM 可使用的最大堆内存。经验之谈*一般设为相等我个人通常会把-Xms和-Xmx设置成一样大比如-Xms4g -Xmx4g。这样做的好处是避免了 JVM 在运行时动态调整堆大小带来的开销减少了 GC 暂停的波动性。*多大合适这没有标准答案得看你的服务类型。计算密集型可能对内存要求不高2-4G 够了。IO密集型、缓存大比如数据查询服务、图片处理服务可能就需要更大的堆8G、16G 甚至更高。服务器总内存的比例通常不超过服务器总内存的 70-80%因为操作系统本身也要内存还有其他进程和 Direct Memory 等。翻车案例早期项目有个兄弟图省事只设了-Xmx没设-Xms。结果服务刚上线时JVM 内存慢慢往上爬频繁触发 Minor GC。最要命的是在业务高峰期GC 停顿突然变长因为 JVM 在动态扩容堆内存时可能会触发一次 Full GC后来果断调整为-Xms等于-Xmx世界才清净了。2. 新生代大小-Xmn或-XX:NewRatio*-Xmnsize直接指定新生代大小。*-XX:NewRatioN设置老年代与新生代的比例。比如NewRatio2表示老年代是新生代的 2 倍即新生代占总堆内存的 1/3。经验之谈*优先-Xmn我更倾向于直接用-Xmn指定新生代大小这样更直观。*比例是关键新生代是对象“出生”的地方大部分对象都是“朝生暮死”的。新生代太小Minor GC 会过于频繁新生代太大老年代就小了可能提前触发 Full GC。通用经验值新生代占整个堆的 1/3 或 1/4 比较常见。如果你的程序产生大量短期对象可以适当增大新生代。3. Survivor 区大小-XX:SurvivorRatio*-XX:SurvivorRatioN Eden 区与一个 Survivor 区的比例。例如SurvivorRatio8意味着 Eden:S0:S1 8:1:1。经验之谈*默认值通常够用除非你对对象晋升老年代的频率有特殊要求一般情况下默认值通常是8就足够了。过大的 Survivor 区会浪费空间过小则可能导致对象过早进入老年代。*关注对象年龄可以结合-XX:MaxTenuringThreshold对象在新生代经历多少次 GC 后晋升老年代来调整。三、 GC 收集器参数谁才是你的“垃圾处理厂”这是调优的重中之重选对 GC 算法事半功倍1. 经典组合JDK 8-XX:UseParallelGC或-XX:UseConcMarkSweepGC*ParallelGC (吞吐量优先)-XX:UseParallelGC配上-XX:ParallelGCThreads指定 GC 线程数。适用场景对吞吐量要求高对短暂停顿不敏感的后台批处理任务、大数据分析。我的评价暴力美学用多线程快速清理垃圾但 STW 停顿时间会比较长。*CMS (低延迟优先已弃用)-XX:UseConcMarkSweepGC适用场景JDK 8 时代对响应时间敏感的应用。我的评价老爷车了时不时来个“并发模式失败”的 Full GC吓死你。强烈不推荐新项目使用。2. 现代选择JDK 9 默认-XX:UseG1GC*G1GC (均衡型)-XX:UseG1GC配上-XX:MaxGCPauseMillisN设置最大 GC 停顿时间目标。适用场景大部分中大型应用尤其是堆内存较大的情况4GB - 32GB。我的评价“万金油”平衡了吞吐量和停顿时间通过分代和区域化管理尽可能做到可控的停顿。这是目前最常用的选择。G1 调优复盘案例某个高并发的微服务初期用的是 CMS经常出现并发模式失败导致 Full GC服务抖动严重。后来切换到 G1并设置了-XX:MaxGCPauseMillis100。虽然不是每次都能达到这个目标但整体停顿时间明显下降服务稳定性大大提高。后来发现G1 还有一个参数-XX:G1HeapRegionSize可以调整 Region 大小一般不需要动但如果对象大小分布极端偶尔也可以微调。3. 未来的黑科技JDK 11-XX:UseZGC或-XX:UseShenandoahGC*ZGC (极低延迟)-XX:UseZGC适用场景对延迟极其敏感的应用如高频交易、游戏服务器、大型缓存服务以及需要支持超大堆内存TB级别的场景。我的评价未来已来颠覆性技术停顿时间基本稳定在 1ms 甚至亚毫秒级简直是黑科技但对 CPU 资源消耗会比 G1 略高一点。需要 JDK 11 以上版本。ZGC 案例分享一个基于 Java 的内存数据库堆内存高达 50GB。以前用 G1虽然也调优过但偶尔的 Minor GC 和 Full GC 还是会导致几百毫秒甚至秒级的停顿直接影响到用户查询体验。切换到 ZGC 后整个世界都清净了GC 停顿几乎感知不到。唯一的“副作用”是监控图上 GC 暂停时间太低以为监控坏了。四、 杂项参数与实用工具“侦探”与“旁观者”除了内存和 GC还有一些参数和工具也能帮我们定位和解决问题。1. GC 日志-Xlog:gc*或-XX:PrintGCDetails等*JDK 9 的新格式-Xlog:gc*:filegc.log。推荐用这个非常详细。*JDK 8 及以前-XX:PrintGCDetails -XX:PrintGCDateStamps -XX:PrintGCTimeStamps -Xloggc:gc.log经验之谈*没日志没真相生产环境一定要开启 GC 日志这是排查 GC 问题的“现场录像”。*分析工具GCViewer、GCEasy等工具可以可视化分析 GC 日志非常直观。2. 堆溢出诊断-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/path/to/dump经验之谈*OOM 必备在发生OutOfMemoryError时自动生成堆转储文件Heap Dump。这个文件是排查内存泄漏的唯一凭证*分析工具MAT (Memory Analyzer Tool)或者VisualVM。3. JIT 编译诊断-XX:PrintCompilation -XX:UnlockDiagnosticVMOptions -XX:PrintInlining经验之谈* 这些参数通常用于深入 JIT 优化原理排查特定方法未被内联或编译的问题。一般生产环境不用开启。*热点代码通过jstat -compiler pid也可以看到 JIT 编译的统计信息。五、 JVM 参数调优的“金科玉律”我的血泪总结没有“万能配置”别指望一套参数能跑所有服务。每个服务都有自己的特点内存模型、对象生命周期、并发量所以必须具体问题具体分析。先基准测试再调优别一上来就猛调参数。先用默认配置跑跑看收集数据找到瓶颈再针对性调优。少量多次逐步调整每次只调整一到两个参数然后观察效果。如果你一口气改了一堆出了问题都不知道是哪个参数引起的。监控监控监控没有监控你根本不知道你的调优有没有效果。CPU、内存、GC 时间、线程数、服务响应时间……这些数据都是你的眼睛。Prometheus Grafana是好搭档高版本 JDK 更好JDK 新版本通常会带来更优秀的 GC 算法比如 ZGC、Shenandoah 的成熟以及 JIT 编译器的性能提升。能升级就升级能省很多力气。业务代码优化永远是第一位JVM 调优只是锦上添花。如果你的业务代码本身就有严重的内存泄漏、线程死锁、低效算法再怎么调 JVM 参数也救不了你。六、 写在最后 JVM 调优是一场没有终点的修行从初期的手足无措到后来的游刃有余JVM 参数调优的经历真的能让人快速成长。它强迫你深入理解 JVM 的底层原理让你从一个只会写业务逻辑的“CRUD Boy/Girl”变成一个能够驾驭系统性能的“架构师”。每一次成功的调优都像是解开一道复杂谜题的成就感。而每一次失败的复盘都让你对 JVM 的理解更上一层楼。所以别害怕那些密密麻麻的 JVM 参数它们不是潘多拉的魔盒而是通往高性能殿堂的钥匙。勇敢地去探索吧少年你的每一次尝试都是在为你的系统注入更强大的生命力好了今天的经验分享就到这里。如果你也遇到过 JVM 调优的奇葩问题或者有什么独家秘籍评论区咱们接着唠期待你的故事… …文末好啦以上就是我这期的全部内容如果有任何疑问欢迎下方留言哦咱们下期见。… …学习不分先后知识不分多少事无巨细当以虚心求教三人行必有我师焉wished for you successed ⭐️若喜欢我就请关注我叭。⭐️若对您有用就请点赞叭。⭐️若有疑问就请评论留言告诉我叭。版权声明本文由作者原创转载请注明出处谢谢支持
返回列表