G1收集器是当今收集器技术发展的最前沿成果之一。它是一款面向服务器应用的垃圾收集器。研发团队希望它未来可以替代掉CMS收集器。
特点:
1.并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU或是CPU核心来缩短stop the world的停顿时间。
2.分代收集:与其它收集器一样,分代概念依然存在,虽然G1可以不需要与其它收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。
3.空间整合:从整体上看,G1是基于“标记-整理”算法实现的和CMS的标记清理不同。而从局部上看两个Region之间用了复制算法。但是无论是哪种算法都不会留下空间碎片,这样就可以保证G1收集器长时间运行,分配大对象时不会因为无法找到连续空间而提前触发下一次GC。
4。可预测停顿:相对于CMS收集器来说G1还有一个优势是可以建立停顿预测模型,这让用户可以在明确指定在一个长度为M毫秒内的时间片段内消耗在垃圾收集时间不超过N毫秒。
内存布局:
G1收集器将整个Java堆分为多个大小相等的独立区域(Region),虽然还留着老年代和新生代的概念,但这两者不在是物理隔离了。
G1之所以高效且停顿时间可预测,是因为收集器有计划的避免在全区域进行垃圾收集,G1跟踪各个Region里面的垃圾堆积价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的回收时间,优先回收价值最大的Region。
但是Region不可能是孤立的,一个对象分配在某个Region中,它并非只能被本Region中的其他对象所引用而是可以与整个Java堆任意的对象发生引用关系。为了避免在做可达性分析时扫描整个Java堆。在G1收集器的Region之间的对象引用以及其它收集器中的新生代与老年代之间的对象引用,虚拟机都是使用Remembered Set来避免全堆扫描的。
G1中每个Region都有一个与之对应的Remembered Set,虚拟机发现程序在对Reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用的对象是否处于不同的Region之中(在分代的例子中就是检查老年代中的对象引用了新生代中的对象),如果是,便通过CardTable把相关引用信息记录到被引用对象所属的Region的Remembered Set之中。当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会有遗漏。
回收过程:
1.初始标记:
仅仅只标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这阶段需要停顿线程,但耗时比较短。
2.并发标记:
该阶段时在用户线程进行时同时并发对堆中对象做可达性分析,找出存活的对象,这阶段耗时长但是并发进行。
3.最终标记:
为了修正在并发阶段因系统继续运行而产生变动得那一部分标记记录。虚拟机将这段时间的变化记录在Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs里的数据合并到Remembered Set里,这阶段可停顿线程,但是可并行执行。
4.筛选回收:
首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个阶段其实也可以和用户线程一起并发执行的,但是因为只回收一部分Region,时间是用户可控制的,而且停下用户线程将大幅提高收集效率。