目录
1、GC过程
2、垃圾回收算法
2.1、标记-清除
2.2、标记-整理
2.3、复制
2.4、分代收集算法
3、TLAB
4、对象如何进入老年代
5、卡片标记
6、HotSpot垃圾回收器
6.1、年轻代垃圾回收器
6.2、老年代垃圾回收器
6.3、如何配置垃圾回收器
6.4、STW
7、CMS垃圾回收器
7.1、定义
7.2、设计目标
7.3、CMS回收过程
7.4、内存碎片
7.5、CMS的停顿(STW)
7.6、CMS缺点
8、G1垃圾回收器
8.1、为什么需要G1?
8.2、G1的设计目标
8.3、CMS和G1的区别?
8.4、G1 有年轻代和老年代的区分吗?
8.5、G1的优点
8.6、G1的数据结构
8.8、G1的垃圾回收过程
8.8.1、年轻代回收(STW)
8.8.2、并发标记
8.8.3、混合回收(Mixed GC)
9、ZGC
先找到活跃的对象,然后把其他不活跃的对象判定为垃圾,然后删除。所以垃圾回收只与活跃的对象有关,和堆的大小无关。
标记存活的对象,然后将未标记的对象统一清除。缺点是会产生内存碎片。
标记存活的对象,然后把整个堆中未标记的对象压缩到堆的其中一块,从而避免了内存的碎片化问题。
将内存一分为二,每次只使用其中一半,满了之后将存活的对象复制到另一半内存中,然后将剩下的碎片一次性擦除。缺点是需要两倍的内存空间。
年轻代 = 1*Eden + 2*survivor
当年轻代中的 Eden 区分配满的时候,就会触发年轻代的 GC(Minor GC)。具体过程如下:
1、在 Eden 区执行了第一次 GC 之后,存活的对象会被移动到其中一个 Survivor 分区(以下简称from);
2、Eden 区再次 GC,这时会采用复制算法,将 Eden 和 from 区一起清理。存活的对象会被复制到 to 区;接下来,只需要清空 from 区就可以了。
所以在这个过程中,总会有一个 Survivor 分区是空置的。Eden、from、to 的默认比例是 8:1:1,所以只会造成 10% 的空间浪费。( -XX:SurvivorRatio 进行配置的(默认为 8))
Thread Local Allocation Buffer,JVM 默认给每个线程开辟一个 buffer 区域,用来加速对象分配。这个 buffer 就放在 Eden 区中。
对象的分配优先在 TLAB上 分配,但 TLAB 通常都很小,所以对象相对比较大的时候,会在 Eden 区的共享区域进行分配。
对象在新生代的GC存活次数阈值:‐XX:+MaxTenuringThreshold(最大为15)。即一个对象,在15次GC后,依然存活,那么将该对象提升到老年代。
当 Survivor 空间不够,就需要依赖其他内存(指老年代)进行分配担保。这个时候,对象也会直接在老年代上分配。
比如,如果幸存区中相同年龄对象大小的和,大于幸存区的一半,大于或等于 age 的对象将会直接进入老年代。
老年代是被分成众多的卡页(card page)的(一般数量是 2 的次幂)。
卡表(Card Table)就是用于标记卡页状态的一个集合,每个卡表项对应一个卡页。
如果年轻代有对象分配,而且老年代有对象指向这个新对象, 那么这个老年代对象所对应内存的卡页,就会标识为 dirty,卡表只需要非常小的存储空间就可以保留这些状态。
垃圾回收时,就可以先读这个卡表,进行快速判断。
Stop the world,在垃圾回收时,暂停用户的一切线程。垃圾回收器是为了让GC时间更短,减少停顿,并不能完全消除停顿。
初始标记(STW状态:(时间短))
1、标记直接关联GC ROOT的对象;
2、标记年轻代中对象的引用。
并发标记(并行)
1、标记所有可达的对象,耗时长,但可与用户线程并行执行。
2、将老年代中发生变化的卡页,标记为dirty状态。
并发预清理(并行)
1、重新标记老年代中状态为dirty的卡页,并清除掉dirty的状态;
2、将老年代中发生变化的卡页,标记为dirty状态。
并发可取消的预清理(可选)(并行)
在满足某些条件的时候,可以终止,比如迭代次数、有用工作量、消耗的系统时间等。
最终标记(SWT)
完成老年代中所有存活对象的标记。(处理老年代中的所有状态为dirty的卡页,且不会再增加新的dirty状态的卡页)
并发清除(并发)
删除不可达对象,并回收空间。(新产生的垃圾对象留待下次GC处理,被称作浮动垃圾)
并发重置(并发)
重置 CMS 算法相关的内部数据,为下一次 GC 循环做准备。
一般情况下,当老年代的使用率达到 70%,就会触发 GC。
可通过参数 -XX:CMSInitiatingOccupancyFraction 用来配置这个比例。
CMS 对老年代回收时,并没有内存的整理阶段。所以,CMS提供了两个参数来解决这个问题:
CMS在发生 Minor GC 时,由于 Survivor 区已经放不下了,多出的对象只能提升(promotion)到老年代。但是此时老年代因为空间碎片的缘故,会发生 concurrent mode failure 的错误。这个时候,就需要降级为 Serail Old 垃圾回收器进行收集。
分而治之,部分收集。
在任意 1 秒的时间内,停顿不得超过 10ms。-XX:MaxGCPauseMillis=10。(控制STW时间)
Rset
CSet
收集集合,保存一次GC中将执行垃圾回收的区间(Region)。
Minor GC,Eden区满的时候,会发生年轻代的垃圾回收。
跨代引用使用 RSet 数据结构来追溯,会一次性回收掉年轻代的所有 Region。
当整个堆内存使用达到一定比例(默认是 45%),并发标记阶段就会被启动。
可通过参数 -XX:InitiatingHeapOccupancyPercent 进行配置。
在 Minor GC 之后,如果判断这个占比达到了某个阈值(垃圾占比),下次就会触发 Mixed GC。这个阈值,由 -XX:G1HeapWastePercent 参数进行设置(默认是堆大小的 5%)。
以上内容为个人学习理解,如有问题,欢迎在评论区指出。
部分内容截取自网络,如有侵权,联系作者删除。