Major GC:有时又叫old gc,只收集old gen
3.3.1 标记-清除算法(老年代回收算法)
标记-清除算法(最基础的算法)分为标记和清除两个阶段:首先标记处所有需要回收的对象,在标记完成之后统一回收所有被标记的对象,它的标记过程其实在前一节讲述对象标记判定时已经介绍过了 。
缺点:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量的不连续的内存碎片,空间碎片较多时会导致以后在程序运行过程中分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作 。

文章插图
3.3.2 复制算法(新生代回收算法)
为了解决效率问题,一种称为复制的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块 。当这一块的内存用完了,就将还存活的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉 。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可 。
优点:实现简单,运行高效 。
缺点:要牺牲内存为代价 。

文章插图
3.3.3 标记-整理算法(老年代回收算法)
由于复制算法在对象存活率较高时存在大量的复制操作,效率降低,而且浪费空间,所以老年代一般不能选择这种算法 。
根据老年代的特点,提出了标记-整理算法,标记过程与标记-清除算法一致,整理过程是先将存活的对象移到一端,然后将存活的对象边界外的内存清理 。

文章插图
3.4 HotSpot的算法实现
3.5 垃圾收集器
3.5.1 Serial收集器
Serial收集器是最基本、发展历史最悠久的收集器,曾经(jdk1.3.1之前)是虚拟机新生代收集的唯一选择 。它是一个单线程的收集器,它使用一个CPU或一条收集线程完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束 。
直到现在为止,它依然是虚拟机运行在CLient模式下的默认新生代垃圾收集器 。
优点:简单而高效,由于运行在单个CPU的环境中,没有线程交互的开销,可以专心做垃圾收集从而获得最高的单线程收集效率 。
缺点:有停顿时间,需要停止所有当前工作线程 。
3.5.2 ParNew收集器
ParNew收集器是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为包括Serial收集器可用的所有控制参数、收集算法和回收策略等和Serial收集器完全一样 。
ParNew收集器是许多运行在Server模式下的虚拟机首选的新生代收集器,其中一个与性能无关的原因是,它能和CMS收集器配合工作 。在JDK1.5时期,HotSpot推出了一款在强交互应用中几乎可认为有划时代意义的垃圾收集器-----------CMS收集器,这款收集器是HotSpot中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程同时工作 。
ParNew收集器在Cpu环境中不会比Serial收集器有更好的效果,甚至由于存在线程交互的开销,该收集器在通过超线程技术实现的两个CPU的环境中都不能百分之百的保证可以超越Serial收集器 。当然随着可以使用的CPU的数量的增加,它对于GC时系统资源的有效利用还是很有好处的 。它默认开启的收集线程数与CPU的数量相同,在CPU非常多的环境下可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数 。
3.5.3 Parallel Scavenge收集器
Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器 。
Parallel Scavenge收集器的特点是它的关注点与其它收集器不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量 。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),虚拟机总共运行了100分钟,垃圾收集1分钟,那吞吐量就是99% 。
Parallel Scavenge收集器拥有自适应的调节策略(GC Ergonomics),它会根据当前系统的运行状况动态调整停顿时间和吞吐量,这也是和ParNew收集器不同之处 。
3.5.4 Serial Old收集器
推荐阅读
- Java 线程池 ThreadPoolExecutor 八种拒绝策略浅析
- B-Tree 数据结构详解及Java代码实现
- Docker容器与虚拟机有什么区别
- Java序列化是什么?你知道什么时候需要序列化吗?
- Java Overload 与 Override 差别
- 详解Java多线程锁之Lock和ReadWriteLock
- Java面向对象——成员变量和局部变量
- java第一次调用 Hadoop Java API
- 2019年最流行的五大JavaScript 自动化测试框架
- Java虚拟机最多支持多少个线程?
