# 频繁 GC

今天分享一个面试题,频繁 GC 怎么处理…

且不说为什么频繁 GC , 先聊聊你怎么发现 JVM 频繁 GC 的呢?

告警啊!对的。
第一种就是 FullGC 的告警,
第二种就是 机器 CPU 的负载过高
第三种就是 大面积的接口超时,无法处理请求。

那就好说了,咱们分析下什么地方可以进行 GC ?

堆! 但不仅仅是堆,还是堆外内存也会进行 GC

当然我们主要说堆!

先看一下常用的名词.

# YoungGC

YoungGC 指发生在新生代的垃圾收集动作,新生代中的对象朝生夕死,所以 Minor GC 非常频繁,回收速度也比较快。频繁的 YoungGC 是正常的,要看下 YoungGC 之后存活的对象是否有问题。

对象优先在新生代 Eden 区中分配,如果 Eden 区没有足够的空间时,就会触发一次 Young GC

新生代的垃圾收集器有 Serial , ParNew .

经过几次 YGC 还存活的就到了老年代。

# old GC

指发生在老年代的 GC ,速度一般比 Minor GC 慢十倍以上。
老年代的垃圾收集器有 Serial Old , Parallel OldCMS .

老年代会在两种情况下触发 Old GC
一是开启分配担保机制,根据历次 Minor GC 后进入老年代的对象大于当前老年代内存大小,判断 Minor GC 有风险,则会触发 Old GC ;比如:

  • 1. 系统并发高、执行耗时过长,或者数据量过大,导致 young gc 频繁,且 gc 后存活对象太多,但是 survivor 区存放不下(太小 或 动态年龄判断) 导致对象快速进入老年代 老年代迅速堆满
  • 2. 程序一次性加载过多对象到内存 (大对象),导致频繁有大对象进入老年代
  • 3. 存在内存溢出的情况,老年代驻留了大量释放不掉的对象, 只要有一点点对象进入老年代 就达到 full gc 的水位了
    二是 Minor GC 后剩余对象太多,老年代放不下了也会触发 Old GC

# Full GC

FGC 收集整个 Young Gen 以及部分 old genGC ,只有垃圾收集器 G1 有这个模式。但是我们通常说的 Full GC 指的是 针对新生代、老年代、永久代的全体内存空间的垃圾回收。

full gc 触发条件有

  • 1、老年代空间不足, 所以追因的方向就是导致 老年代空间不足的原因:
    大量对象频繁进入老年代 + 老年代空间释放不掉
  • 2、元空间内存不足,也会触发 Full GC
  • 3、堆外内存 direct buffer memory 使用不当导致
  • 4、代码问题。老年代占用不高,重启效果不明显。这种情况,大概率是在代码里搞执行了 System.gc() ;

# 解决

知道了上面的问题之后,解决就简单了。

  • 1、观察年轻代 gc 的情况,多久执行一次、每次 gc 后存活对象有多少 survivor 区多大
    存活对象比较多 超过 survivor 区大小或触发动态年龄判断 => 调整内存分配比例
  • 2、观察老年代的内存情况 水位情况,多久执行一次、执行耗时多少、回收掉多少内存
    如果在持续的上涨,而且 full gc 后回收效果不好,那么很有可能是内存溢出了 => 查看堆快照,定位内存溢出位置,修复代码。
  • 3、如果年轻代和老年代的内存都比较低,而且频率低,那么有可能是元数据区加载太多东西了

# 最后

更新于 阅读次数

请我喝[咖啡]~( ̄▽ ̄)~*

方小白 微信支付

微信支付

方小白 支付宝

支付宝

方小白 numberpay

numberpay