1 serial垃圾回收器是最早的,这个收集器是单线程的,所谓单线程,是指它在回收时,会暂停其他所有线程,直到它收集结束。由于单线程处理垃圾回收,没有线程切换的开销,所以效率很高,对应内存不大的比较合适,例如运行在客户端模式下的虚拟机来说是个很好的选择。
serial old收集器:它是serial的老年代收集器,采用的是标记-整理,可以和Parallel Scavenge搭配使用,也可以作为CMS收集器发生失败时的后背预案
2 ParNew收集器:相对于serial收集器,它是并行的,在JDK 7之前是首选的新生代收集器,因为只有它能和CMS收集器配合工作
3 Parallel Scavenge收集器:是新生代收集器,基于标记复制算法实现的,它的目标是达到一个可控制的吞吐量,,高的吞吐量(用户代码和垃圾收集中共消耗100分钟,如果垃圾回收用了一分钟,那吞吐量就是99%)可以高效的利用处理器资源
Parallel old收集器:Parallel Scavenge的老年代,标记-整理算法
4 CMS收集器:JDK 5发布的CMS收集器是真正意义上实现了支持并发的垃圾收集器,它首次实现了让垃圾收集器与用户线程同时工作,适用与老年代收集,新生代需要适用serial或parnew,无法与JDK 1.4中的Parallel Scavenge配合;它的目标是回收停顿时间最短的收集器,大部分java应用集中在互联网网站或基于浏览器的B/S系统的服务端,需要快速响应,基于标记-清除算法
步骤:
a 初始标记:需要停顿用户线程,只是标记gc roots能直接关联到的对象
b 并发标记:就是从gc roots的直接关联对象开始遍历整个对象图的过程,可以和垃圾收集线程并发运行
c 重新标记 :为了修改并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录
d 并发清除:清理删除掉标记阶段已经死亡的对象,由于不需要移动存活对象,所以可以与用户线程并发运行
缺点:由于并发运行,会占用资源,降低吞吐量;并发标记和并发清除阶段,用户程序也在运行,这期间也可能有新的垃圾对象不断产生,由于标记过程已经结束,这部分垃圾只能放在下次收集;由于并发运行,所以无法等到老年代内存块用完时进行回收必须预留一部分给线程使用。
由于它是基于标记-清除算法,所以会导致空间碎片,如果分配大对象可能触发垃圾回收,它提供了一个参数usecms -compactAtAullCollection(默认开启,1.9废弃)用于cms收集器不得不进行full gc时开启内存碎片合并整理过程,由于必须移动对象,所以无法并发,虽然空间碎片解决了,但是停顿时间变长
5 g1收集器:g1收集器是一个面向全堆的收集器,不需要其他新生代收集器配合工作;开创了面向局部收集的设计思路和基于Region的内存布局形式;它不再局限与新生代或是老年代,它可以面向堆内存任何部分来组成回收集进行回收,衡量的标准是哪块内存中存放的垃圾数量最大,回收收益最大;它还是遵循分代收集理论设计,只是把连续的java堆划分为多个大小相等的独立区域,每个区域都可以根据需要去扮演新生代eden,survivor,老年代,根据扮演的角色不同的区域采用不同的策略去处理,所以无论新建的还是老年代的都可以收集,而且它还有专门的区域去存放大对象,只要超过区域一半大小的容量即判定为大对象,也可以通过G1HeapRegionSize去设置;针对g1的存在跨区域的引用,其实也是记忆集,只是它本质上是使用哈希表,key是region的起始地址,value是集合,里面存储的元素是卡表的索引号,是一种双向的卡表结构,我指向了谁,谁指向了我;
它通过原始快照的算法实现用户线程改变引用关系时,保证其不打破原来的对象图结构,导致标记错误
g1收集器的步骤:
a 初始标记:标记一下gc roots能直接关联的对象,修改tams指针值,让下一阶段用户线程并发运行阶段,能正确地可用的region分配新对象
b 并发标记:从gc roots开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象
c 最终标记:对用户线程进行短暂暂停,用户处理并发阶段结束后遗留的少量satb(快照)记录
d 筛选回收:可以只有选择任意多个region进行回收,把决定回收的那部分region的存活对象复制到空的region中,在清理旧的region全部空间,必须暂停用户,有多条收集线程执行。
从整体上看,基于标记-整理;从region上看,基于标记-复制
6 日志:jdk 9前使用PrintGC ,jdk 9 后,使用-Xlog:gc: