1、Serial(新生代收集器)
单线程, 新生代标记-复制算法
额外内存最小,因为是单线程,在内核数少的情况下,效率很高。
运行于客户端的JVM首选
2、ParNew(新生代收集器)
多线程并行版Serial,标记-复制算法
多核心处理器下效率优异,单核处理器环境下不如Serial。
JDK7之前,服务端新生代首选垃圾回收器。
可以与老年代:CMS回收器配合使用
3、Parallel Scavenge(新生代收集器)
并行收集的多线程收集器,标记-复制算法
侧重于吞吐量
区别于ParNew收集器的一个重要特性:自适应调节策略
4、Serial Old(老年代收集器)
单线程,标记-整理算法。
CMS收集器失败的后备预案。
主要可运行于客户端
5、Parallel Old(老年代收集器)
多线程并发收集,基于标记-整理算法实现。
JDK6开始提供。此前Parallel Scavenge 只能和Serial Old搭配。因Serial Old 性能不高,无法实现吞吐量最优。
JDK6之后,吞吐量优先时,可配合Parallel Scavenge使用。
7、CMS(Concurrent Mark Sweep) (老年代收集器)
并发收集、低停顿,标记-清除算法实现
JDK5发布,区别于Parallel Scavenge,侧重于最短回收停顿时间(Stop The World的时间)
CMS收集器运作过程:
1)初始标记 stop the world,标记GC Roots直接关联的对象
2)并发标记 根据直接关联的对象,遍历对象图。耗时长,并发运行,不停顿用户线程。
3)重新标记 stop the world,修正并发标记阶段(解决方案:增量更新算法),用户线程变动的对象标记。防止“对象消失”问题。
4)并发清除 清理删除掉标记阶段判断的已死亡对象。因不需要移动存活对象,可并发处理。
因并发标记、并发清除这两个耗时最久的阶段,都可与用户线程并发执行。所以从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。实现的低停顿目标。
缺点:
1)并发处理,需要线程执行,抢占了一部分用户线程(处理器计算能力),导致吞吐量降低,直观感受就是用户觉得页面反应慢了。
2)无法处理在并发标记期间,用户线程产生的浮动垃圾。因需要预留一部分空间给用户线程,所以不能在老年代几乎填满时整理。
可通过参数-XX:CMSInitiatingOccupancyFraction设置CMS启动阈值,JDK6之后CMS收集器的启动阈值默认为92%。
一旦CMS运行时,预留给用户线程的空间不足,就会出现“并发失败”。JVM这时候会启动备案,冻结用户线程。使用Serial Old收集器重新进行老年代的垃圾收集。
3)标记-清除算法会产生空间碎片。没有连续空间分配给大对象时,会提前Full GC。
为解决这个问题,CMS提供了参数:-XX:+UseCMS-CompactAtFullCollection,用于在Full GC时,合并整理内存碎片。
但移动内存存活对象会Stop the world,停顿时间变长,所以CMS提供了另外的参数-XX:CMSFullGCsBefore-Compaction,可以要求CMS在指定次数内,不进行内存整理。
8、Garbage First(G1)(全功能垃圾收集器、高吞吐量)
并发收集,总体标记-整理,局部(两个Region 之间)标记-复制。Mixed GC,JDK9提供,主要面向服务端。服务端模式下的默认垃圾收集器。
新生代及老年代都是动态由小块内存的Region拼接(不需要连续),新生代及老年代的大小不固定。参数-XX:G1HeapRegionSize 可设置Region的大小(范围1M~32M,且应为2的N次幂)
大对象(超过Region的一半)由Humongous区存储,超过1个Humongous的,会由多个连续的Humongous区存储。
后台维护优先列表,优先处理回收价值收益最大的那些Region。
G1收集器的运作过程:
1)初始标记 stop the world(很短) 标记一下GC Roots能直接关联到的对象,并且修改TAMS 指针的值,指导下一阶段用户线程在Region的哪部分创建新对象。
2)并发标记 可达性分析,递归扫描整个堆里的对象图。可与用户线程并发执行。扫描完成后,重新处理SATB记录里,并发时有引用变动的对象。(原始快照(SATB)算法处理,防止“对象消失”问题。)
3)最终标记 stop the world 对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。
4)筛选回收 stop the world 排序回收Region性价比,根据用户期望停顿时间制定回收计划,两个Region 之间标记-复制,多条收集器线程并行。
9、Shenandoah(全功能垃圾收集器、低延迟)
区别于G1:
1)支持并发整理算法,G1筛选回收阶段可并行,但不可以与用户线程并发。CAS保证并发对象的访问正确性。
2)Shenandoah默认不使用分代。
3)Shenandoah记录跨Region引用的方法是采用“连接矩阵”
Shenandoah收集器运行过程:
1)初始标记 stop the world(很短) 标记GC Roots能直接关联到的对象。
2)并发标记 与G1一样,遍历对象图,标记出全部可达的对象。
3)最终标记 stop the world(很短) 与G1一样,处理剩余的SATB扫描,并在这个阶段统计出回收价值最高的Region,将这些Region构成一组回收集。最终标记阶段也会有一小段短暂的停顿。
4)并发清理 这个阶段用于清理那些整个区域内连一个存活对象都没有找到的Region。
5)并发回收 通过读屏障和被称为“*s Pointers”的转发指针来并发回收,标记-复制算法,复制存活对象。
6)初始引用更新 stop the world(短暂) 建立一个线程集合点,确保所有并发回收阶段中进行的收集器线程都已完成分配给它们的对象移动任务。
7)并发引用更新 按照内存物理地址的顺序,线性搜索出堆中引用类型,把旧值改为新值。进行引用更新。
8)最终引用更新 stop the world(很短) 解决了堆中的引用更新后,还要修正存在于GC Roots 中的引用。这个阶段是Shenandoah的最后一次停顿,停顿时间只与GC Roots的数量相关。
9)并发清理 清理回收集中所有的Region(这些Region里无人生还),以供新对象分配空间使用。
10、ZGC(全功能垃圾收集器、低延迟)
ZGC收集器是一款基于Region内存布局的,(暂时) 不设分代的,使用了读屏障、染色指针和内存多重映射等技术来实现可并发的标记-整理算法的,以低延迟为首要目标的一款垃圾收集器。
ZGC的Region分为 小、中、大Region。大Region容量并不固定,用于存储唯一1个4MB或以上的大对象。无法被重分配。
ZGC的核心问题——并发整理算法的实现,采用染色指针,JVM通过指针看到其引用对象的三色标记状态、是否进入了重分配集(即被移动过)、是否只能通过finalize()方法才能被访问到。由于占用指针宽度,压缩了地址空间,直接导致ZGC能够管理的内存不可以超过4TB。
染色指针优势:
1)某个Region的存活对象被移走之后,这个Region立即就能够被释放和重用,而不必等待整个堆中所有指向该Region的引用都被修正后才能清理。
2)染色指针可以大幅减少在垃圾收集过程中内存屏障的使用数量,因此对吞吐量的负面影响较低。
3)染色指针可以作为一种可扩展的存储结构用来记录更多与对象标记、重定位过程相关的数据,以 便日后进一步提高性能。
ZGC运作过程:
1)并发标记 ZGC根据指针,遍历对象图。标记阶段会更新染色指针中的Marked 0、Marked1标志位。
2)并发预备重分配 扫描全堆Region,省去G1中记忆集的维护成本。统计要清理的Region。
3)并发重分配 执行复制,过程中为每一个Region维护转发表。当用户访问被复制的对象时,内存屏障截获后,转发到新的对象地址,同时更新该引用值。某Region全部复制完毕后,立即释放。原分配表保留。
4)并发重映射 修正所有旧指针,释放原分配表。(合并到了下一次垃圾收集循环中的并发标记阶段里去完成)
11、Epsilon(无操作收集器)
只保证,堆的管理和对象的分配。
对于应用只要运行数分钟甚至数秒, 只要Java虚拟机能正确分配内存,在堆耗尽之前就会退出,
运行负载极小、没有任何回收行为 的Epsilon便是很恰当的选择