望牛墩镇网站建设公司成都住建局官网查询入口
2026/4/12 6:54:39 网站建设 项目流程
望牛墩镇网站建设公司,成都住建局官网查询入口,华为公司邮箱是多少,阿里云 企业网站选哪种一、问题背景 某天下午#xff0c;运维收到生产环境告警#xff1a;某业务系统的定时任务服务 CPU 使用率飙升至 90%#xff0c;服务响应变慢#xff0c;部分定时任务执行超时。 告警信息#xff1a; [ALERT] xxx-schedule 服务 CPU 使用率 92.3% [ALERT] xxx-schedule …一、问题背景某天下午运维收到生产环境告警某业务系统的定时任务服务 CPU 使用率飙升至 90%服务响应变慢部分定时任务执行超时。告警信息 [ALERT] xxx-schedule 服务 CPU 使用率 92.3% [ALERT] xxx-schedule 服务 Full GC 次数: 15次/分钟 [ALERT] syncDataJob 执行超时耗时: 180s二、问题现象2.1 GC 日志分析登录服务器查看 GC 日志tail -100f /logs/xxx-schedule/gc.log2026-01-11T14:32:15.2340800: [Full GC (Ergonomics) [PSYoungGen: 87296K-0K(153088K)] [ParOldGen: 349568K-298456K(349696K)] 436864K-298456K(502784K), [Metaspace: 128456K-128456K(1169408K)], 2.3456789 secs] 2026-01-11T14:32:18.1230800: [Full GC (Ergonomics) [PSYoungGen: 87296K-0K(153088K)] [ParOldGen: 348234K-301234K(349696K)] 435530K-301234K(502784K), [Metaspace: 128456K-128456K(1169408K)], 2.5678901 secs] 2026-01-11T14:32:21.4560800: [Full GC (Ergonomics) [PSYoungGen: 87296K-0K(153088K)] [ParOldGen: 349012K-305678K(349696K)] 436308K-305678K(502784K), [Metaspace: 128456K-128456K(1169408K)], 2.7890123 secs]关键发现Full GC 频繁触发约 3 秒一次老年代使用率持续在 85% (298456K/349696K)每次 Full GC 后老年代释放空间有限呈上涨趋势GC 耗时较长2.3s ~ 2.8s2.2 使用 jstat 观察jstat -gcutil 1000 10S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 98.23 45.67 86.34 94.12 91.23 1234 12.345 156 312.456 324.801 0.00 0.00 78.90 87.56 94.12 91.23 1235 12.456 157 315.234 327.690 0.00 97.45 12.34 88.91 94.12 91.23 1236 12.567 158 318.012 330.579分析O (老年代) 持续增长86% → 87% → 88%FGC 次数快速增加FGCT (Full GC 总时间) 占 GCT 的 96%三、定位过程3.1 Dump 堆内存# 生成堆转储文件 jmap -dump:formatb,file/tmp/heap_dump_20260111.hprof# 或者使用 jcmd推荐 jcmd GC.heap_dump /tmp/heap_dump_20260111.hprof3.2 使用 MAT 分析导入 Eclipse MAT (Memory Analyzer Tool) 分析Leak Suspects 报告Problem Suspect 1:The thread xxl-job, JobThread-15-1704960000000 keeps local variables with total size 156,789,456 bytes (45.2% of total heap). Keywords: java.util.ArrayList, java.util.HashMapDominator Tree 分析3.3 追踪到具体代码通过 MAT 的 “Path to GC Roots” 功能定位到内存持有路径Thread: xxl-job, JobThread-15-1704960000000└── SyncDataJob.handler() └── dataList (ArrayList) └── HashMap (156MB) └── Order objects (300,000 条)四、根因分析4.1 问题代码定位查看 SyncDataJob.javaXxlJob(“syncDataJob”) public ReturnT handler(){log.info(数据同步Job开始执行); Long minId 0L; while (true) { // 问题1: 每次查询100条但内存中累积了所有处理过的数据 ListMapString, Object dataList orderMapper.selectByPage(minId, BATCH_SIZE); if (CollectionUtils.isEmpty(dataList)) { break; } // 问题2: 循环内创建大量临时对象 for (MapString, Object data : dataList) { MapString, Object map new HashMap(); // 每条记录创建新Map // ... 填充数据 ListMapString, Object paramList new ArrayList(); paramList.add(map); // 调用外部服务 externalService.process(paramList); } // 更新minId继续下一批 minId dataList.stream() .map(d - ((Number) d.get(id)).longValue()) .max(Long::compareTo) .orElse(minId); } return ReturnT.SUCCESS;}4.2 问题分析问题一MyBatis 查询返回 Map 类型触发自定义 TypeHandler项目配置了全局 TypeHandler mybatis.type-handlers-packagecom.xxx.domain.typehandlerJsonTypeHandler 会拦截 Map 类型尝试将每个列值反序列化MappedJdbcTypes(JdbcType.VARCHAR) public class JsonTypeHandler extends BaseTypeHandler {private MapString,String map new TreeMap(); // 每次实例化都创建 Override public Map getNullableResult(ResultSet resultSet, String s) throws SQLException { return this.toObject(resultSet.getString(s), map.getClass()); // 频繁创建TreeMap }}问题二循环内频繁创建临时对象每处理一条记录就创建1 个 HashMap (约 200 bytes)1 个 ArrayList (约 88 bytes)若干 String 对象当数据量大时如 30 万条产生大量短生命周期对象导致 Young GC 频繁部分对象晋升到老年代。问题三数据量估算– 查询符合条件的数据量 SELECT COUNT(1) FROM order_info WHERE status 0; – 结果: 324,567 条五、解决方案5.1 修复 TypeHandler 冲突5.2 优化内存使用XxlJob(“syncDataJob”) public ReturnT handler(){ log.info(数据同步Job开始执行); Long minId 0L; // 复用对象 MapString, Object map new HashMap(16); ListMapString, Object paramList new ArrayList(1); while (true) { ListMapString, Object dataList orderMapper.selectByPage(minId, BATCH_SIZE); if (CollectionUtils.isEmpty(dataList)) { break; } for (MapString, Object data : dataList) { map.clear(); // 复用Map Long id ((Number) data.get(id)).longValue(); minId Math.max(minId, id); // 填充数据... map.put(orderId, data.get(orderId)); // ... paramList.clear(); paramList.add(map); externalService.process(paramList); } // 显式释放引用帮助GC dataList.clear(); dataList null; log.info(处理了一批数据当前minId{}, minId); } return ReturnT.SUCCESS; }5.3 JVM 参数调优# 原参数 -Xms512m -Xmx512m -XX:UseParallelGC # 优化后 -Xms1g -Xmx1g -XX:UseG1GC -XX:MaxGCPauseMillis200 -XX:G1HeapRegionSize8m -XX:InitiatingHeapOccupancyPercent45 -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/logs/xxx-schedule/六、效果验证6.1 修复后 GC 情况jstat -gcutil 1000 10S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 45.23 23.45 34.56 92.34 89.12 234 4.567 2 0.234 4.801 0.00 0.00 56.78 34.78 92.34 89.12 235 4.678 2 0.234 4.912 0.00 43.21 12.34 35.12 92.34 89.12 236 4.789 2 0.234 5.023对比七、经验总结7.1 排查流程告警触发 → GC日志分析 → jstat观察 → heap dump → MAT分析 → 代码定位 → 修复验证7.2 常见 Full GC 原因内存泄漏对象被长生命周期引用持有大对象分配直接进入老年代TypeHandler/序列化问题隐式创建大量临时对象批处理未分批一次性加载过多数据MetaSpace 不足类加载过多7.3 预防措施代码规范批量处理必须分页循环内避免频繁创建对象监控告警配置 GC 次数、老年代使用率告警定期审查review MyBatis resultType、TypeHandler 配置压测验证大数据量场景必须压测7.4 常用排查命令速查# 查看 GC 统计 jstat -gcutil 1000# 查看堆内存使用 jmap -heap# 生成堆转储 jcmd GC.heap_dump /tmp/dump.hprof# 查看线程栈 jstack /tmp/thread_dump.txt# 查看类加载统计 jmap -histo | head -50

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询