问题排查

CPU 利用率高

频繁GC、死循环

解决

  1. top -Hp 定位CPU 最高的进程
  2. printf '0x%x' tid 线程 id 转化 16 进制
  3. jstack pid | grep tid 找到线程堆栈

内存问题

GC

正常的堆内存曲线应该是呈锯齿形,如果发现 full gc 之后堆内存几乎没有下降,那么可以推断:堆中有大量不能回收的对象且在不停膨胀,使堆的使用占比超过full GC的触发阈值,但又回收不掉,导致full GC一直执行,可能是内存泄露。

G1 发生 full GC

  • 并发阶段失败:在并发标记阶段,MixGC之前老年代就被填满了,那么这时候G1就会放弃标记周期。这种情况,可能就需要增加堆大小,或者调整并发标记线程数-XX:ConcGCThreads
  • 晋升失败:在GC的时候没有足够的内存供存活/晋升对象使用,所以触发了Full GC。这时候可以通过-XX:G1ReservePercent来增加预留内存百分比,减少-XX:InitiatingHeapOccupancyPercent来提前启动标记,-XX:ConcGCThreads来增加标记线程数也是可以的。
  • 大对象分配失败:大对象找不到合适的region空间进行分配,就会进行fullGC,这种情况下可以增大内存或者增大-XX:G1HeapRegionSize

内存泄露

通过jstack和jmap定位问题

原因

  1. 长生命周期的对象持有短生命周期的引用(作用域过大)
    • 对不再使用的对象赋值为null
  2. 没有使用close()
  3. Set、Map 容器没用重写 equals 方法
  4. 单例模式是一个长生命周期的对象。如果这个对象持有其他对象的引用,也很容易发生内存泄露。