Skip to content

面试题蒸馏卡:应用服务内存与CPU爆满排查

问题:应用服务内存或 CPU 爆满的发生场景?遇到这种问题怎么处理?

一句话机制

服务"爆满"本质是资源供给 < 资源消耗速率:内存侧是对象分配快于 GC 回收(泄漏/大对象)或堆外无上限;CPU 侧是单/多线程长期 100% 执行有效指令(死循环/FGC/锁竞争/密集计算)。排查核心:先定性(内存 or CPU)→ 定位热点(线程/对象)→ 反推代码

1. 内存爆满(OOM / 堆只涨不降)

发生场景

  • 内存泄漏:静态集合只增不删、本地缓存无 TTL/容量上限、ThreadLocal 用完未 remove、连接/流未关闭、监听器未注销
  • 大对象瞬间吃满:一次性 SELECT * 全表、大文件读入 byte[]、深分页、超大 JSON 反序列化
  • 突发流量:缓存击穿 → DB 压力 → 线程堆积 → 堆涨
  • JVM 参数不当-Xmx 过小;堆外(NIO DirectBuffer/Metaspace/线程栈)无上限 → 堆没满但进程被 OS kill
  • 第三方库 bug:恶意/超大文本 JSON 解析

怎么定位

bash
top / htop                      # 找高内存 PID
top -Hp <pid>                   # 看哪个线程最忙
jstat -gcutil <pid> 1s          # FGC 频繁 + 老年代接近 100% → 泄漏信号
jmap -histo:live <pid> | head   # 对象实例数 Top,定位泄漏类型
jmap -dump:live,format=b,file=heap.hprof <pid>  # 导堆
# MAT / jhat 分析支配树、GC Roots 路径
jcmd <pid> VM.native_memory     # 堆外(NMT)

线上优先 Arthasdashboard / heapdump / thread / memory,免重启。

怎么处理

  • 修泄漏点(缓存加 TTL+容量、ThreadLocal 配对 remove、用池化/流式)
  • 大对象改分页/游标/流式读写
  • 调参:合理 -Xmx-XX:MaxMetaspaceSize-XX:MaxDirectMemorySize
  • 限流 + 降级 + 熔断,防流量冲垮内存

2. CPU 爆满

发生场景

  • 死循环 / 递归无终止、正则灾难性回溯(a+)+$ 类)
  • 频繁 FGC(内存泄漏引发,CPU 被 GC 线程吃满)
  • 锁竞争/自旋、同步粒度粗、大量线程上下文切换
  • 加密/压缩/序列化密集、大对象 JSON 解析
  • 外部调用慢 → 线程池打满 → 大量超时重试

怎么定位

bash
top -Hp <pid>                   # 高 CPU 线程的 tid
printf "%x\n" <tid>             # 转 16 进制
jstack <pid> | grep -A 30 <nid> # 看该线程栈,定位代码行
# Arthas: thread -n 3           # 直接看最忙的 3 个线程
# async-profiler / perf        # 火焰图定位热点方法

怎么处理

  • 修死循环/优化正则(加原子组、限制回溯)
  • 降锁粒度、用无锁结构、限流防线程堆积
  • 异步化、缓存热点、扩容

追问链(面试官会怎么接着问)

  1. 内存和 CPU 爆满的共同根因是什么? 先排除流量尖峰,再怀疑代码 bug——外部流量 vs 内部泄漏/死循环。
  2. 怎么快速区分内存泄漏还是突发流量? 老年代"只涨不落"、FGC 后回收不掉 → 泄漏;QPS 曲线同步涨 → 流量。
  3. Arthas 常用哪几个命令? dashboard(总览)/ thread -n 3(最忙线程)/ heapdump(导堆)/ watch(方法入参出参)。
  4. Full GC 频繁但堆没满,可能是什么? 堆外 DirectBufferMetaspace 满、或被显式 System.gc() 调用。
  5. 怎么证明是某集合泄漏而非别的原因? MAT 看支配树(Dominator Tree)+ GC Roots 路径,找到"谁还引用着这个大对象"。

常见误解

  • ❌ "CPU 100% 一定是死循环" —— 也可能是频繁 FGC、锁竞争、加密/序列化密集。
  • ❌ "OOM 就是 -Xmx 太小" —— 堆外内存/Metaspace/线程栈无上限也会 OOM,且堆没满也能被 OS kill。
  • ❌ "top 看 RES 高就是泄漏" —— 可能是缓存正常占用,关键看是否持续增长且不随 GC 回落

关联

最近更新