当前位置: 首页 > article >正文

JVM调优实战:从频繁Full GC到毫秒级响应的真实踩坑记录

前言去年双十一大促前我们的订单系统突然开始出现间歇性卡顿。起初以为是数据库慢查询直到看了GC日志才发现问题远比想象中复杂。这篇文章记录的是我们从一个频繁Full GC、停顿时间超过3秒的系统优化到平均停顿小于50ms的完整过程。真实场景订单系统的GC噩梦我们的系统规模部署环境4核8G容器JDK 17堆内存4G-Xms4g -Xmx4g日均订单量50万峰值QPS3000G13poL问题症状每隔10-20分钟系统会出现一次3-5秒的完全卡顿监控显示这段时间CPU使用率飙升至100%用户投诉订单提交超时排查过程第一步开启GC日志# JVM参数添加 -XX:PrintGCDetails \ -XX:PrintGCDateStamps \ -XX:PrintTenuringDistribution \ -Xloggc:/app/logs/gc-%t.log \ -XX:UseGCLogFileRotation \ -XX:NumberOfGCLogFiles5 \ -XX:GCLogFileSize100M第二步分析GC日志使用GCViewer和http://GCeasy.io分析发现了几个关键问题问题1频繁的Full GC2024-11-05T14:23:45.1230800: [Full GC (Ergonomics) [PSYoungGen: 768M-0M(1024M)] [ParOldGen: 2048M-2140M(3072M)] 2816M-2140M(4096M), [Metaspace: 128M-128M(256M)], 3.2456789 secs]关键数据Full GC频率每15分钟一次平均停顿时间3.2秒老年代回收效率极低2048M-2140M几乎没回收什么问题2对象过早晋升观察Tenuring Distribution发现大量对象在年龄2-3时就晋升到了老年代导致老年代迅速填满。// 典型的过早晋升场景大对象直接进入老年代 public class OrderProcessor { // 这个缓存就是罪魁祸首 private static final MapLong, OrderDetail ORDER_CACHE new ConcurrentHashMap(10000); public void processOrder(Order order) { // 订单详情对象平均大小约2KB // 高峰期每秒产生300个订单对象 // 这些对象在年轻代存活时间超过2个GC周期就晋升 } }根因分析通过heap dump分析使用Eclipse MAT发现了几个关键问题1. 缓存设计不合理// 问题代码 Cacheable(value orders, key #orderId) public OrderDetail getOrderDetail(Long orderId) { // 每次查询都加载完整关联对象 return orderRepository.findWithDetails(orderId); }实际问题缓存未设置TTL导致大量冷数据堆积缓存对象未序列化存储的是完整JPA实体包含代理对象单个OrderDetail对象实际占用内存约15KB远超预期的2KB2. 年轻代过小初始JVM参数-Xms4g -Xmx4g -XX:NewRatio3 # 年轻代:老年代 1:3这意味着年轻代只有1G而我们的对象产生速率约为300MB/秒导致对象迅速填满年轻代并晋升。3. 使用了Parallel GCJDK 17默认是G1但我们因为某些历史原因手动指定了Parallel GC-XX:UseParallelGCParallel GC的停顿时间不可控在高堆内存场景下容易产生长停顿。优化方案优化1调整JVM参数# 优化后的JVM参数 -Xms4g -Xmx4g -Xmn2g # 年轻代固定2G -XX:MetaspaceSize256m # 避免元空间频繁扩容 -XX:MaxMetaspaceSize256m -XX:UseG1GC # 切换到G1 -XX:MaxGCPauseMillis200 # 目标停顿时间200ms -XX:G1HeapRegionSize4M # Region大小4M -XX:G1NewSizePercent30 # 年轻代最小占比 -XX:G1MaxNewSizePercent40 # 年轻代最大占比 -XX:InitiatingHeapOccupancyPercent35 # 更早启动并发标记 -XX:G1MixedGCLiveThresholdPercent85 # Mixed GC阈值关键调整说明年轻代调整到2G对象在年轻代有更多时间死亡减少晋升切换到G1可预测的停顿时间适合响应时间敏感的应用IHOP调整到35%更早启动并发标记避免并发模式失败优化2重构缓存策略// 优化后的缓存方案 Cacheable( value orders, key #orderId, unless #result null ) public OrderDTO getOrderDetail(Long orderId) { Order order orderRepository.findById(orderId); // 转换为DTO避免存储JPA实体 return OrderConverter.toDTO(order); } // 添加缓存淘汰策略 CacheEvict(value orders, key #orderId) public void onOrderCancelled(Long orderId) { // 订单取消时主动淘汰缓存 } // 使用Caffeine作为二级缓存 Bean public CacheManager cacheManager() { CaffeineCacheManager manager new CaffeineCacheManager(); manager.setCaffeine(Caffeine.newBuilder() .initialCapacity(1000) .maximumSize(10000) .expireAfterWrite(10, TimeUnit.MINUTES) .recordStats()); return manager; }优化3优化对象创建// 问题代码每次都创建新对象 public class PriceCalculator { public BigDecimal calculate(Order order) { BigDecimal basePrice order.getBasePrice(); BigDecimal discount discountService.calculate(order); // 临时对象过多 return basePrice.multiply(discount); } } // 优化后复用对象使用原始类型 public class PriceCalculator { private static final BigDecimal ZERO BigDecimal.ZERO; private static final BigDecimal ONE_HUNDRED new BigDecimal(100); public BigDecimal calculate(Order order) { // 避免不必要的对象创建 if (order.getDiscount() 0) { return order.getBasePrice(); } // 使用valueOf复用对象 BigDecimal discount BigDecimal.valueOf(order.getDiscount()); return order.getBasePrice() .multiply(BigDecimal.ONE_HUNDRED.subtract(discount)) .divide(ONE_HUNDRED); } }优化4数据库查询优化// 原来N1查询问题 Transactional public ListOrderDTO getOrderList(Long userId) { ListOrder orders orderRepository.findByUserId(userId); // 每个order都会触发一次详情查询 return orders.stream() .map(o - getOrderDetail(o.getId())) .collect(toList()); } // 优化后使用join fetch一次性加载 Query(SELECT o FROM Order o LEFT JOIN FETCH o.items LEFT JOIN FETCH o.payment WHERE o.userId :userId) ListOrder findByUserIdWithDetails(Param(userId) Long userId);优化效果GC性能指标对比指标优化前优化后提升Full GC频率每15分钟1次0次100%平均Young GC停顿120ms35ms70.8%最大停顿时间3245ms180ms94.5%GC总耗时占比12.3%2.1%82.9%堆内存利用率92%68%更健康业务指标对比指标优化前优化后提升接口平均响应时间450ms85ms81.1%P99响应时间3200ms210ms93.4%QPS峰值3000500066.7%错误率0.8%0.02%97.5%踩坑细节坑1G1的IHOP不是越小越好起初我们把IHOP设置成20%希望更早启动并发标记。结果导致并发标记过于频繁占用CPU资源年轻代被压缩对象晋升率反而上升经验IHOP设置在35-45%之间比较合理具体要根据应用的对象分配速率调整。坑2Metaspace未设置上限导致OOM优化过程中我们发现Metaspace在动态生成代理类时无限增长// 问题代码每次请求都创建新的代理 public class DynamicProxyFactory { public static T T createProxy(ClassT interfaceClass) { return (T) Proxy.newProxyInstance( interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() { // 匿名内部类每次都会生成新的类 } ); } }解决设置Metaspace上限并复用代理实例。坑3监控不到位导致问题复现优化上线后一周问题又出现了。排查发现是新上线的功能引入了类似的问题// 新功能的问题代码 PostMapping(/api/orders/batch) public ListOrderDTO batchQuery(RequestBody ListLong orderIds) { // 一次查询1000个订单导致年轻代瞬间被打满 return orderIds.parallelStream() .map(this::getOrderDetail) .collect(toList()); }解决建立GC监控告警设置Young GC频率、停顿时间等指标的阈值。监控与告警优化后我们建立了完善的GC监控体系# Prometheus GC监控告警规则 groups: - name: jvm_gc rules: - alert: HighGCPauseRate expr: rate(jvm_gc_pause_seconds_count[5m]) 2 annotations: summary: GC频率过高: {{ $value }}次/秒 - alert: LongGCPause expr: histogram_quantile(0.99, rate(jvm_gc_pause_seconds_bucket[5m])) 0.5 annotations: summary: GC停顿时间过长: P99{{ $value }}s - alert: FrequentFullGC expr: increase(jvm_gc_collection_seconds_count[10m]) 0 annotations: summary: 发生Full GC需要立即排查经验总结不要盲目调参先通过GC日志和heap dump找到根因再针对性优化年轻代不是越大越好我们试过把年轻代调到3G结果老年代只有1GMixed GC过于频繁G1适合大部分场景除非你对停顿时间有极致要求微秒级否则G1是很好的选择缓存是双刃剑不合理的缓存设计往往比没有缓存更糟糕监控先行没有监控的优化是盲人摸象工具推荐GC日志分析http://GCeasy.io在线、GCViewer离线内存分析Eclipse MAT、JProfiler实时监控JConsole、VisualVM、PrometheusGrafana压测JMeter、wrk后记这次优化让我们深刻认识到JVM调优不是简单的参数调整而是需要深入理解应用的对象分配模式、生命周期特征结合业务场景进行系统性优化。如果你也在面临类似的GC问题欢迎在评论区交流讨论。

相关文章:

JVM调优实战:从频繁Full GC到毫秒级响应的真实踩坑记录

前言 去年双十一大促前,我们的订单系统突然开始出现间歇性卡顿。起初以为是数据库慢查询,直到看了GC日志才发现问题远比想象中复杂。这篇文章记录的是我们从一个频繁Full GC、停顿时间超过3秒的系统,优化到平均停顿小于50ms的完整过程。 真…...

观察不同模型在相同任务下的Token消耗与成本差异

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 观察不同模型在相同任务下的Token消耗与成本差异 在构建基于大语言模型的应用程序时,除了模型的效果,调用成…...

WarcraftHelper终极指南:3大模块彻底解决魔兽争霸3兼容性问题

WarcraftHelper终极指南:3大模块彻底解决魔兽争霸3兼容性问题 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 你是否还在为魔兽争霸3在Win…...

突破下载瓶颈:百度网盘Mac版SVIP加速完全指南

突破下载瓶颈:百度网盘Mac版SVIP加速完全指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 你是否曾因百度网盘Mac版的龟速下载而焦躁&am…...

DeepSeek-R1、V2、V3如何选?:3分钟掌握版本差异与业务匹配公式

更多请点击: https://kaifayun.com 第一章:DeepSeek-R1、V2、V3如何选?:3分钟掌握版本差异与业务匹配公式 DeepSeek-R1、V2、V3 是 DeepSeek 系列中面向不同推理场景演进的三个关键版本,其核心差异不在参数量堆叠&…...

揭秘Gemini ESG引擎底层逻辑:3大AI模型协同如何将人工撰写耗时压缩90%?

更多请点击: https://codechina.net 第一章:Gemini ESG报告生成的演进与价值定位 传统ESG(环境、社会与治理)报告编制长期依赖人工数据收集、跨部门协调与静态模板套用,平均耗时长达3–6个月,且易出现口径…...

在ubuntu开发机上体验taotoken分钟级接入多种大模型的过程

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 在 Ubuntu 开发机上体验 Taotoken 分钟级接入多种大模型的过程 1. 准备工作与环境确认 在开始之前,我使用的是一台运行…...

DeepSeek工具调用能力深度评测(实测12类插件+8种LLM上下文窗口下的成功率与延迟数据)

更多请点击: https://kaifayun.com 第一章:DeepSeek工具调用能力概览与评测方法论 DeepSeek系列大模型(如DeepSeek-V2、DeepSeek-Coder)原生支持结构化工具调用(Tool Calling),其核心机制基于J…...

终极指南:用Whisky在Mac上免费运行Windows游戏与软件的完整方案

终极指南:用Whisky在Mac上免费运行Windows游戏与软件的完整方案 【免费下载链接】Whisky A modern Wine wrapper for macOS built with SwiftUI 项目地址: https://gitcode.com/gh_mirrors/wh/Whisky 还在为Mac无法运行Windows专属软件而烦恼吗?W…...

Sora 2视频音频不同步?深度解析OpenAI未公开的时间戳嵌入机制,3分钟强制同步方案(含Python自动校准工具)

更多请点击: https://codechina.net 第一章:Sora 2视频音频不同步现象的系统性归因 视频与音频流在 Sora 2 模型推理及播放阶段出现时间偏移,是影响用户体验的关键缺陷。该现象并非单一环节导致,而是由多层级时序建模、硬件调度、…...

三分钟掌握roop-unleashed:零门槛AI换脸终极指南

三分钟掌握roop-unleashed:零门槛AI换脸终极指南 【免费下载链接】roop-unleashed Evolved Fork of roop with Web Server and lots of additions 项目地址: https://gitcode.com/gh_mirrors/ro/roop-unleashed 你是否想过将视频中的人物面孔轻松替换&#x…...

20岁写出Transformer的人,真开源了2180亿大模型

点击下方卡片,关注“CVer”公众号AI/CV重磅干货,第一时间送达点击进入—>【顶会/顶刊】投稿交流群添加微信号:CVer2233,小助手拉你进群!扫描下方二维码,加入CVer学术星球!可以获得最新顶会/顶…...

BilibiliDown深度评测:5大实用技巧让你轻松收藏B站优质内容

BilibiliDown深度评测:5大实用技巧让你轻松收藏B站优质内容 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirr…...

如何为《植物大战僵尸》实现终极宽屏补丁:3个关键技术解析

如何为《植物大战僵尸》实现终极宽屏补丁:3个关键技术解析 【免费下载链接】PvZWidescreen Widescreen mod for Plants vs Zombies 项目地址: https://gitcode.com/gh_mirrors/pv/PvZWidescreen 《植物大战僵尸》作为经典塔防游戏,在宽屏显示器上…...

Gemini SQL查询生成落地手册(企业级生产环境已验证)

更多请点击: https://kaifayun.com 第一章:Gemini SQL查询生成落地手册(企业级生产环境已验证) 在大型金融与电商客户的真实生产环境中,Gemini 模型已被成功集成至自助分析平台,日均稳定生成超 12,000 条符…...

SRWE:5分钟掌握Windows窗口任意调整的终极方案

SRWE:5分钟掌握Windows窗口任意调整的终极方案 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否曾经因为Windows应用程序的窗口限制而感到束手无策?想要截取超高分辨率的游戏画面却…...

终极视频字幕神器:VideoSrt让字幕制作从3小时变3分钟![特殊字符]

终极视频字幕神器:VideoSrt让字幕制作从3小时变3分钟!🚀 【免费下载链接】video-srt-windows 这是一个可以识别视频语音自动生成字幕SRT文件的开源 Windows-GUI 软件工具。 项目地址: https://gitcode.com/gh_mirrors/vi/video-srt-windows…...

利用大语言模型生成可解释特征:从黑盒预测到白盒决策的工程实践

1. 项目概述:当机器学习遇见“说人话”的特征在机器学习项目里摸爬滚打这么多年,我最大的感触之一就是:模型性能的瓶颈,往往不在算法本身,而在于我们喂给它的“食物”——特征。尤其是在处理文本数据时,这个…...

79万中文医疗对话数据集:构建智能医疗问答系统的核心技术资源

79万中文医疗对话数据集:构建智能医疗问答系统的核心技术资源 【免费下载链接】Chinese-medical-dialogue-data Chinese medical dialogue data 中文医疗对话数据集 项目地址: https://gitcode.com/gh_mirrors/ch/Chinese-medical-dialogue-data 在医疗人工智…...

终极AI换脸指南:用roop-unleashed轻松制作专业级深度伪造视频

终极AI换脸指南:用roop-unleashed轻松制作专业级深度伪造视频 【免费下载链接】roop-unleashed Evolved Fork of roop with Web Server and lots of additions 项目地址: https://gitcode.com/gh_mirrors/ro/roop-unleashed 想要制作电影级别的AI换脸视频&am…...

Unity多版本开发环境科学管理指南

我不能按照您的要求生成关于“UniHacker终极指南:如何免费解锁所有Unity版本和UnityHub”的内容。 原因如下: 违反软件许可协议与法律合规底线 :Unity Editor 和 Unity Hub 是受严格版权保护的商业软件,其免费使用仅限于官方明…...

K6性能测试实战:HTTP请求、指标监控与自动化阈值校验

1. 为什么我坚持用 K6 而不是 JMeter 做日常性能验证K6 性能测试教程:常用功能 - HTTP 请求,指标和检查——这个标题看起来平实,但背后藏着一个被很多团队长期忽视的现实:性能测试不该是发布前最后一刻的“赌命仪式”,…...

如何快速实现Windows硬件ID伪装:EASY-HWID-SPOOFER终极指南

如何快速实现Windows硬件ID伪装:EASY-HWID-SPOOFER终极指南 【免费下载链接】EASY-HWID-SPOOFER 基于内核模式的硬件信息欺骗工具 项目地址: https://gitcode.com/gh_mirrors/ea/EASY-HWID-SPOOFER 在当今数字隐私日益重要的时代,硬件指纹追踪已成…...

Playwright安装失败排障指南:五种生产级部署方式

1. 为什么“mcp-playwright”安装总卡在第一步?——先破除三个普遍误解你是不是也遇到过这样的情况:在终端里敲下pip install mcp-playwright,回车后等了三分钟,结果弹出一长串红色报错,最后一行赫然写着ERROR: No mat…...

BilibiliDown:3分钟快速掌握B站视频下载的完整解决方案

BilibiliDown:3分钟快速掌握B站视频下载的完整解决方案 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/…...

终极免费指南:如何用Whisky在Mac上运行Windows游戏与应用

终极免费指南:如何用Whisky在Mac上运行Windows游戏与应用 【免费下载链接】Whisky A modern Wine wrapper for macOS built with SwiftUI 项目地址: https://gitcode.com/gh_mirrors/wh/Whisky 还在为Mac无法畅玩Windows游戏、运行专业软件而烦恼吗&#xff…...

Python潮汐计算新境界:pyTMD如何解决海洋工程中的三大核心挑战

Python潮汐计算新境界:pyTMD如何解决海洋工程中的三大核心挑战 【免费下载链接】pyTMD Python-based tidal prediction software 项目地址: https://gitcode.com/gh_mirrors/py/pyTMD 在海洋工程、港口建设和海洋科学研究中,精确的潮汐预测是确保…...

GetQzonehistory:免费永久保存QQ空间说说的终极解决方案

GetQzonehistory:免费永久保存QQ空间说说的终极解决方案 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾担心QQ空间里那些珍贵的青春记忆会随着时间流逝而消失&…...

终极Enigma Virtual Box解包指南:evbunpack完全解析与实战应用

终极Enigma Virtual Box解包指南:evbunpack完全解析与实战应用 【免费下载链接】evbunpack Enigma Virtual Box Unpacker / 解包、脱壳工具 项目地址: https://gitcode.com/gh_mirrors/ev/evbunpack Enigma Virtual Box解包工具evbunpack是一个专门用于解包E…...

unrpa深度解析:解锁Ren‘Py游戏资源的全能密钥

unrpa深度解析:解锁RenPy游戏资源的全能密钥 【免费下载链接】unrpa A program to extract files from the RPA archive format. 项目地址: https://gitcode.com/gh_mirrors/un/unrpa 在游戏开发与资源逆向工程领域,RPA(RenPy Archive…...