什么情况下jvm会执行young gc? young gc 怎么工作的?

233 阅读3分钟

前言

通常jvm调优调的就是gc的频率, 而其中次级重要的是针对 young gc 频率的调整, 一般 30 - 60 分钟执行一次 young gc 为底线, 最好是几个小时执行一次 所以我们来聊聊什么情况下会执行 young gc

博客没查任何资料, 均为口述, 可能存在不正确的地方, 请指出, 相护学习

本章内容

  1. 什么是young gc?
  2. 什么时候触发 young gc?
  3. young gc 怎么工作的?

什么是young gc?

young gc 又称作 minor gc, 表示面向新生代的垃圾收集器, 主要收集一些引用不可达对象

什么时候触发 young gc?

触发 young gc 的条件主要有这些

eden区满了, 会执行young gc

在执行young gc我记得还会检查下老年代的内存状态:

  • 看下老年代的内存是否充足;
  • 老内存到内存是否过于碎片化;

这样做的目的是如果新生代 young gc之后, 还存在大量对象幸存, 导致survivor to区无法存储, 此时就会触发担保机制, 将部分对象直接存放到 老年代, 在放到老年代前需要对老年代的内存进行判断, 判断老年代内存是否足够存放young gc 的对象, 一般按照前几次young gc进入老年代对象内存的平均值作为判断老年代是否能够保存young gc 过来的对象能够保存到老年代; 如果老年代内存不足, 则会触发一次 full gc, 整理下老年代的内存碎片, 再保存, 至于以前-XX: HandlePromotionFailure参数已经失效了, 不用管什么冒险操作

young gc 怎么工作的?

young gc的垃圾收集算法一般是 标记-复制 算法

标记复制 算法

image.png

假设存在200mb的内存, 如果使用标记复制算法, 就将 200 mb 内存平均分为两个 100mb 内存块, A块内存100mb, B块内存 100 mb

对象创建将会进入其中A块内存块, 直到A块内存块不足, 触发 young gc 标记复制算法

标记存活的对象, 然后将存活的一堆对象复制到 B 块内存块, 注意这里的复制是依次复制到B块内存块, 防止出现内存碎片

存在内存碎片:

image.png

依次复制防止出现内存碎片:

image.png

优点

不会出现内存碎片

缺点

  1. 占用内存居多, 浪费了一半的内存
  2. 如果幸存的对象特别多, 那么就会复制很久的时间

使用场景

合适百分之99的对象朝生夕死, 一次 gc 后对象 100 个只剩下 1 个存活, 这种情况很合适 标记复制 算法

新生代的内存布局情况

image.png

内存布局情况为 eden区 survivor(from)区 和 survivor(to)区, 内存占比为 8 : 1 : 1

比例可以通过-XX:Survivor-Ratio=8参数修改, 如果是-XX:Survivor-Ratio=6, 则表示 eden区 : survivor(from)区 为 6 : 1

如果新生代内存为 100 mb , 那么

  • eden区为 100 / (6 + 1 + 1) * 6 = 75 mb
  • survivor (from) 或者 to 区为 100 / (6 + 1 + 1) * 1 = 12.5 mb

所以young gc怎么工作的就非常简单了

当eden区满时,新对象无法进入eden区,此时就会触发young gc

young gc触发就会标记 survivor from区和 eden 区中幸存的对象,然后将这些对象复制到survivor to区(此时to区是空的)

如果to区不足以存放这么对象就会回到上面说的担保机制

总结

young gc还有很多没讲,比如serial收集器或者parallel 收集器或者parallel scavenge收集器parallel scavenge收集器等但这些都不重要就不讲了 当然如果你使用的是jdk8,那么可以了解了解parallel scavenge收集器