前言
通常jvm调优调的就是gc的频率, 而其中次级重要的是针对 young gc 频率的调整, 一般 30 - 60 分钟执行一次 young gc 为底线, 最好是几个小时执行一次 所以我们来聊聊什么情况下会执行 young gc
博客没查任何资料, 均为口述, 可能存在不正确的地方, 请指出, 相护学习
本章内容
- 什么是young gc?
- 什么时候触发 young gc?
- 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的垃圾收集算法一般是 标记-复制 算法
标记复制 算法
假设存在200mb的内存, 如果使用标记复制算法, 就将 200 mb 内存平均分为两个 100mb 内存块, A块内存100mb, B块内存 100 mb
对象创建将会进入其中A块内存块, 直到A块内存块不足, 触发 young gc 标记复制算法
标记存活的对象, 然后将存活的一堆对象复制到 B 块内存块, 注意这里的复制是依次复制到B块内存块, 防止出现内存碎片
存在内存碎片:
依次复制防止出现内存碎片:
优点
不会出现内存碎片
缺点
- 占用内存居多, 浪费了一半的内存
- 如果幸存的对象特别多, 那么就会复制很久的时间
使用场景
合适百分之99的对象朝生夕死, 一次 gc 后对象 100 个只剩下 1 个存活, 这种情况很合适 标记复制 算法
新生代的内存布局情况
内存布局情况为 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收集器