
一、内存相关最常见、最致命1.内存泄漏Memory Leak现象堆内存只涨不跌Full GC 后不下降最终 OOM根本原因对象被长期持有static 集合、ThreadLocal、线程池、连接未释放后果服务卡死、重启才能恢复判断方法jstat -gc看到老年代持续上涨Full GC 后内存不下降监控曲线堆内存只增不减最终抛出OOM: Java heap space定位泄露代码导出堆快照# 自动导出推荐OOM 时自动 dump不影响运行 -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/tmp/heap.hprofMAT分析看引用链解决方法打断引用链手动设置null、调用 remove/clear/close加自动清理机制过期时间、最大容量、淘汰策略使用安全工具类try-with-resources、规范线程池截止无界缓存、无界集合应急方法重启服务dump命令输出内存信息修复、上线预防机制代码规范ThreadLocal 必 remove连接必关闭禁止使用 static 集合做本地缓存缓存必须用Caffeine、Guava、Redis开启监控堆内存、Full GC 次数代码 review 重点检查缓存、线程池、IO2.内存溢出 OOM根本原因内存泄漏、大对象、堆设置太小常见的OOM堆溢出Java heap spaceGC 超时溢出 GC overhead limit exceeded解决方法禁止一次性加载大量数据分页、分批、流式处理禁止无界缓存不用 static Map 做缓存资源必须关闭合理使用线程池1.2.1. 堆内存溢出现象报错java.lang.OutOfMemoryError: Java heap space原因一次查询全表数据几十万、上百万条内存泄漏耗光堆堆内存设置太小大对象大 List、大文件、大报文解决方法临时扩容快速恢复代码根治SQL 必须分页查询禁止select *全表加载修复内存泄漏static 集合、ThreadLocal 等大文件流式处理不要一次性读入内存检查是否有超大对象、超大集合元空间溢出Metaspace直接内存溢出1.2.2. GC 超时溢出现象GC 占用太多 CPU回收不掉内存直接抛 OOM原因:内存快耗尽Full GC 疯狂跑99% 是内存泄漏解决方法按内存泄漏流程排查清理无用对象引用适当加大堆内存3.GC 频繁 / Full GC 频繁(几分钟一次甚至几十秒一次)现象CPU 飙升、接口响应慢、TP99 暴涨根本原因内存泄漏、新生代太小、大对象直接进入老年代判断方法jps # 找到进程 PID 、jstat -gc PID 1s # 实时看 GCYGC 飙升→ 新生代问题FGC 飙升 老年代涨→内存泄漏 / 堆太小FGC 后内存不下降→100% 内存泄漏解决方法急救5 分钟恢复重启服务、临时加大堆内存加 JVM 参数YGC 频繁 → 加大 -XmnFGC 频繁 → 加大堆 Xmx或使用 G1FGC 频繁 内存不下降 → 内存泄漏必须改代码高并发接口 → 新生代给大一点1/2 堆业务对象多、缓存多 → 老年代给大一点定位根因jstat 看 FGC 是否频繁有泄漏 → MAT 分析无泄漏 → 调大内存 优化代码代码根治分页查询禁止全表加载ThreadLocal 必须 remove连接 / 流必须关闭static 集合不能无限增长线程池必须用有界队列二、CPU 相关极易触发告警1.CPU 使用率过高100%/80%Top 原因及解决方法Full GC 疯狂执行占 70%通过jstat -gc PID xxx 命令确认。如果 FGC 疯狂上涨、秒秒都在 GC→CPU 高 GC 导致如果 GC 正常、YGC/FGC 都不高→CPU 高 业务代码导致代码死循环找到代码加结束条件大量线程锁竞争减少锁粒度、使用无锁结构、分段锁复杂计算 / 正则 / 序列化优化正则、拆分、限制长度后果服务不响应、雪崩2.1.1. GC 导致 CPU 高最常见现象jstat 看到 FGC 频繁上涨GC 线程把 CPU 打满解决方法直接做加大堆内存按之前的 Full GC 频繁方案处理排查内存泄漏导出 dumpMAT 分析2.1.2. 业务代码导致 CPU 高真正要查代码排查方法找到耗 CPU 的 Java 进程 —— top命令找到PID找到进程内最耗 CPU 的线程 —— top -Hp PID拿到线程TID把线程 ID 转成 16 进制 —— printf %x\n TID导出线程栈定位代码行 —— jstack 16进制结果 cpu.log2.死锁 / 锁竞争激烈现象接口卡住、线程大量 WAITING根因synchronized 嵌套、ReentrantLock 未释放、线程池设计不合理定位直接查死锁自动检测jstack -l PID lock.log打开日志搜索关键字 Found 1 deadlock看锁竞争jstack PID | grep -C 10 WAITING大量线程 WAITING 且都等同一个锁地址→锁竞争激烈解决方法统一锁的获取顺序使用定时锁避免无限等待减少嵌套锁不要锁中锁无锁设计ThreadLocal、CAS加锁粒度拆小低效锁推荐高效锁synchronized 全局锁ReentrantLock普通 HashMapConcurrentHashMap自己写的锁LongAdder计数独占锁读写锁 ReadWriteLock三、接口 / 业务性能用户感知最强1.接口响应慢 / TP99 飙升最常见原因慢 SQL没索引、连表太深外部接口调用超时Redis 缓存失效 / 击穿锁等待、GC 停顿大事务、长事务定位看监控链路追踪Arthas看哪一段耗时最高是 DBHTTPRedis还是业务代码抓慢接口日志无监控也能查grep -r 接口名 app.log | grep 耗时偶尔慢GC / 锁还是一直慢SQL / 外部调用Arthas 一键定位# 查看方法耗时 —— trace 类名 方法名# 查看慢调用 —— watch 类名 方法名 {params,returnObj,throwExp} -n 5 -x 3 cost1003.1.1. 慢 SQL / DB 慢最常见现象接口 TP99 突然飙升数据库 CPU 高、连接池等待日志里 SQL 执行几十几百毫秒解决方法加索引、分页查询、大SQL拆分、加缓存3.1.2. 外部接口调用慢HTTP/Dubbo现象调用第三方服务、支付、短信、其他微服务超时、响应慢、不稳定解决方法加超时时间、熔断降级、异步化、加缓存3.1.3. Redis 问题现象缓存击穿、缓存雪崩Redis 命令慢高并发下缓存失效请求打到 DB解决方法缓存穿透 / 击穿加布隆过滤器、空值缓存缓存雪崩过期时间加随机值、集群部署大 Key 优化避免超大 Hash、List2.线程池耗尽 / 异步任务堆积因果关系任务堆积→ 处理不过来队列满了 最大线程数也满了→线程池耗尽报错RejectedExecutionException根因线程池参数不合理、任务阻塞、消费不过来直观判断日志大量抛拒绝执行异常异步任务不执行、延迟极高接口被拖慢、雪崩定位arthas-boot.jar threadpool看到 活动线程数、队列堆积数、任务执行耗时解决方法调整队列大小建议200~500根据并发调整优化线程池参数CPU 密集型计算最大线程 CPU 核数 1IO 密集型HTTP、DB、Redis最大线程 50~200更换拒绝策略推荐CallerRunsPolicy队列满了 →让调用者自己执行不会丢任务、不会雪崩相当于自动限流优化任务执行速度SQL 慢 → 加索引HTTP 调用慢 → 加超时、熔断锁等待 → 缩粒度、换无锁外部调用慢 →异步化、并行化终极解决方案高并发异步任务太多 → 用 MQ 削峰最稳任务不直接扔线程池发送到 RabbitMQ / RocketMQ / Kafka消费者慢慢消费彻底解决堆积、耗尽、雪崩四、连接 / 资源泄漏隐形杀手1.连接泄漏DB/Redis/HTTP现象运行一段时间后无法获取连接根因连接获取后未关闭、try-with-resources Java 7 专门用来解决资源泄漏未使用2.文件句柄 / 流未关闭现象导致 Too many open files结果服务崩溃无法重启解决使用 try-with-resources所有流、文件、连接自动关闭