用于对老年代进行回收,目的是尽量减少应用的停顿时间、减少full gc发生的几率、是基于标记清除算法实现的,整体分为四个阶段
标记GC Roots可达的老年代对象
遍历新生代对象,标记可达的老年代对象。
该阶段GC线程和应用线程并发执行,遍历初始阶段标记出来的存活对象,然后继续递归标记这些对象可达的对象。
因为该阶段并发执行的,在运行期间可能发生新生代的对象晋升到老年代、或者是直接在老年代分配对象、或者更新老年代对象的引用关系等情况,对于这些对象需要重新标记以免发生漏标的情况, 为了提高重新标记的效率,该阶段会把上述对象所在的Card标识为Dirty,后续只需扫描这些Dirty Card的对象,避免扫描整个老年代。
遍历新生代对象,重新标记,根据GC Roots,重新标记,遍历老年代的Dirty Card,重新标记.
清除没有被标记的对象并回收空间
是面向服务端应用的分代垃圾收集器分为Young GC和Mixed gc,将整个java堆划分为多个大小相等的独立区域(region),新生代和老年代不是物理隔离的,它们都是一部分region不连续的集合。
每个region都有一个与之对应的remembered set,jvm发现程序在对reference类型的数据进行写操作时,会产生一个write barrier暂时中断写操作,检查reference引用的对象是否处于不同的region中
,如果是通过cardTable把相关引用信息记录到被引用对象属于的region的remembered set之中,当进行内存回收时,在gc根据加入remember set 避免对全堆的扫描也不会遗漏,回收过程大致分为四步
1:初始标记(stw):标记gc roots能直接关联到的对象,并修改tams的值,让下一阶段用户程序在并发运行时能在正确可用的region中创建对象。
2:并发标记:从gc roots开始对堆中对象进行可达性分析,找出存活的对象。
3:最终标记(STW):标记在并发标记阶段发生变化的对象,将这些对象记录在线程的remembered set logs里面,并将remembered set logs的数据合并到remembered set中。
4:筛选回收:清除空Region(没有存活对象的),加入到free list.
第一阶段initial mark是共用了Young GC的暂停,这是因为他们可以复用root scan操作,所以可以说global concurrent marking是伴随Young GC而发生的。第四阶段Cleanup只是回收了没有存活对象的Region,所以它并不需要STW。
为什么G1可以做到回收时间用户可以设定
答:G1收集器将整个java堆划分为多个大小相等的region,G1跟踪各个region里垃圾堆积的价值大小,在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的region
,利用region划分内存空间以及优先级的区域回收方式,保证在有限的时间内可以获得更高的收集率。
G1中的GC模式
Young GC:选定所有年轻代里的Region。通过控制年轻代的region个数,即年轻代内存大小,来控制young GC的时间开销。
Mixed GC:选定所有年轻代里的Region,外加根据global concurrent marking统计得出收集收益高的若干老年代Region。在用户指定的开销目标范围内尽可能选择收益高的老年代Region
如果mixed GC实在无法跟上程序分配内存的速度,导致old gen填满无法继续进行mixed GC,就会切换到G1之外的serial old GC来收集整个GC heap(注意,包括young、old、perm)。这才是真正的full GC。
cms收集器的缺点:
1:对cpu资源敏感:在并发阶段,虽然不会影响用户线程停顿,但是会占用部分cup资源,导致应用程序变慢,降低总吞吐量。
2:基于标记清楚法会产生大量的碎片。
2:G1收集器,相对于cms收集器而言有如下优势
1:能充分利用多核cpu优势
2:分代收集,CMS收集器用于老年代收集器需要配合seria或者Parallel来完成新生代的收集
3:整体基于标记整理法,局部基于复制算法。
4:可预测停顿。
最后补充下可作为GC Roots对象的包括如下几种:
1:虚拟机栈(栈帧中的本地变量表)中引用的对象
2:方法区中类静态属性引用对象。
3:方法区中常量引用对象。
4:本地方法栈中JNI(一般说的Native方法)引用的对象。