赞
踩
在G1之前的其他收集器进行收集的范围都是整个新生代或者老年代,而G1不再是这样。在堆的结构设计时,G1打破了以往将收集范围固定在新生代或老年代的模式,G1将堆分成许多相同大小的区域单元,每个单元称为Region,Region是一块地址连续的内存空间,并且新生代和老年代的大小也不是固定的了可以根据需要扮演eden suvivor 或者 old。还有一个humongous区存储大对象。G1模块的组成如下图所示:
G1收集器将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。Region的大小是一致的,数值是在1M到32M字节之间的一个2的幂值数,JVM会尽量划分2048个左右、同等大小的Region。
G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在整个Java堆中进行全区域的垃圾收集。G1会通过一个合理的计算模型,计算出每个Region的收集成本并量化,这样一来,收集器在给定了“停顿”时间限制的情况下,总是能选择一组恰当的Regions作为收集目标,让其收集开销满足这个限制条件,以此达到实时收集的G1收集的运作过程大致如下:
停顿线程
,但耗时很短。停顿线程
,但是可并行执行。G1中不仅采用了Card Table,还使用了remember set用来跟踪对象引用,避免扫描所有Region。
下图展示的是RSet与Card的关系。简单来说Region由多个Card组成,且每个Region初始化时,会初始化一个remembered set,用来记录其他Region指向自己对象的引用。同样的,JVM会截获引用类型数据的写操作,每次写操作会产生一个写屏障,中断并检查引用的对象Card是否存在于不同的region中,并更新被引用对象的RSet。所以RSet实际记录的是某个Region的某个Card。
当 GC 发生时,通过 RSet 找到引用当前 Region 的 Old Regions 的某个Card进行扫描,避免了扫描全部的 Old Regions,提高扫描效率。
RSet和Card其实解决了不同维度的问题:前者解决回收老年代时需要扫描所有Old Region的问题,后者解决回收新生代出现跨代引用时需要扫描全部老年代的问题。可以把Card Table理解成内存分页的标识位,RSet理解成记录内存页关系的链表
优点:
缺点:
通常来说小内存适合使用CMS,大内存适合使用G1,堆内存的平衡点在6GB~8GB
https://juejin.cn/post/6844903974676463629
《深入理解java虚拟机 第3版》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。