垃圾回收器
1.垃圾回收器概述
- 如果说收集算法是内存回收的方法论,那么收集器就是内存回收的实践者.
- 垃圾收集器没有在 java 虚拟机规范中进行过多的规定,可以由不同的厂商、 不同版本的 JVM 来实现。
- 由于 JDK 的版本处于高速迭代过程中,因此 Java 发展至今已经衍生了众多 的 GC 版本。
- 从不同角度分析垃圾收集器,可以将 GC 分为不同的类型。
2.垃圾回收器分类
按线程数分,可以分为串行垃圾回收器和并行垃圾回收器
串行回收指的是在同一时间段内只允许有一个 CPU 用于执行垃圾回收操作,此时工作线程被暂停,直至垃圾收集工作结束。
和串行回收相反,并行收集可以运用多个 CPU 同时执行垃圾回收,因此提 升了应用的吞吐量,不过并行回收仍然与串行回收一样,采用独占式,使用 "stop-the-world"机制。
按照工作模式分,可以分为并发式垃圾回收器和独占式垃圾回收器。
并发式垃圾回收器与应用程序线程交替工作,以尽可能减少应用程序的停顿 时间。独占式垃圾回收器(stop the world)一旦运行,就停止应用程序中的所有 用户线程,直到垃圾回收过程完全结束。
按工作的内存区间分,又可分为年轻代垃圾回收器和老年代垃圾回收器。
3. GC性能指标
- 吞吐量:运行用户代码的时间占总运行时间的比例(总运行时间:程序的运 行时间+内存回收的时间)
- 垃圾收集开销:垃圾收集所用时间与总运行时间的比例。
- 暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间。
- 收集频率:相对于应用程序的执行,收集操作发生的频率。
- 内存占用:Java 堆区所占的内存大小。
- 快速:一个对象从诞生到被回收所经历的时间。
4.HotSpot垃圾收集器
图中展示了 7 种作用于不同分代的收集器,如果两个收集器之间存在连线,则说明它们可以搭配使用。虚拟机所处的区域则表示它是属于新生代还是老年代收集器。
- 串行回收器:Serial,Serial old
- 并行回收器:ParNew,Parallel scavenge,Parallel old
- 并发回收器:CMS、G1
- 新生代收集器:Serial,ParNew.Parallel scavenge;
- 老年代收集器:Serial old.Parallel old.cMS;
- 整堆收集器:G1;
(1)Serial 垃圾收集器(单线程)
Serial收集器是最基本的、新生代的、发展历史最悠久的收集器。
特点: 单线程、简单高效,采用复制算法,对于限定单个 CPU 的环境来说,Serial 收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收 集效率。收集器进行垃圾回收时,必须暂停其他所有的工作线程,直到它结束 (Stop The World)。
应用场景: 适用于Client(客户) 模式下的虚拟机。
Serial / Serial Old 收集器运行示意图
(2)Serial Old 垃圾收集器(单线程)
Serial Old 是 Serial 收集器的老年代版本。
特点: 同样是单线程收集器,采用标记-整理算法。
应用场景: 主要也是使用在 Client 模式下的虚拟机中。也可在 Server 模式下使用。
(3)ParNew 垃圾收集器(多线程)
ParNew 收集器其实就是 Serial 收集器的多线程版本。
除了使用多线程外其余行为均和 Serial 收集器一模一样(参数控制、收集算法、Stop The World、对象分配规则、回收策略等)。
特点: 多线程、ParNew 收集器默认开启的收集线程数与 CPU 的数量相同,在 CPU 非常多的环境中,可以使用-XX:ParallelGCThreads 参数来限制垃圾收集 的线程数。和 Serial 收集器一样存在 Stop The World 问题。
应用场景: ParNew 收集器是许多运行在 Server 模式下的虚拟机中首选的新生 代收集器,因为它是除了 Serial 收集器外,唯一一个能与 CMS 收集器配合工作的。
ParNew/Serial Old 组合收集器运行示意图如下:
(4)Parallel Scavenge 垃圾收集器(多线程)
Parallel Scavenge 和 ParNew 一样,都是多线程、新生代垃圾收集器。 但是两者有巨大的不同点:
Parallel Scavenge:追求 CPU 吞吐量,能够在较短时间内完成指定任务, 因此适合没有交互的后台计算,。
(5)Parallel Old 垃圾收集器(多线程)
是 Parallel Scavenge 收集器的老年代版本。
特点: 多线程,采用标记-整理算法。
应用场景: 注重高吞吐量以及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge+Parallel Old 收集器。
(6)CMS 回收器(低延迟)
CMS(Concurrent Mark Sweep,并发标记清除)收集器是以获取最短回收停顿 时间为目标的收集器(追求低停顿),它在垃圾收集时使得用户线程和 GC 线程并 发执行,因此在垃圾收集过程中用户也不会感到明显的卡顿。
- 初始标记:Stop The World,仅使用一条初始标记线程对所有与 GC Roots 直 接关联的对象进行标记。
- 并发标记:使用多条标记线程,与用户线程并发执行。此过程进行可达性分析, 标记出所有废弃对象。速度很慢。
- 重新标记:Stop The World,使用多条标记线程并发执行,将刚才并发标记过 程中新出现的废弃对象标记出来。
- 并发清除:只使用一条 GC 线程,与用户线程并发执行,清除刚才标记的对象。 这个过程非常耗时。
并发标记与并发清除过程耗时最长,且可以与用户线程一起工作,因此,总体上 说,CMS 收集器的内存回收过程是与用户线程一起并发执行的。
CMS的优点:
- 并发收集
- 低延迟
CMS的弊端:
- 会产生内存碎片, 导致并发清除后,用户线程可用的空间不足。在无法分配 大对象的青况下,不得不提前触发 Ful1 GC.
- CMS 收集器对 CPU 资源非常敏感。 在并发阶段,它虽然不会导致用户停顿, 但是会因为占用了一部分线程而导致应用程序变慢,总吞吐量会降低。
(7)G1(Garbage First)回收器(区域划分代式)
既然我们已经有了前面几个强大的 GC,为什么还要发布 Garbage First(G1) GC呢?
原因就在于应用程序所应对的业务越来越庞大、复杂,用户越来越多,没有 GC 就不能保证应用程序正常进行,而经常造成 STW 的 GC 又跟不上实际的需 求,所以才会不断地尝试对 GC 进行优化。G1(Garbage-First)垃圾回收器是在 Java7 update 4 之后引入的一个新的垃圾回收器,是当今收集器技术发展的 最前沿成果之一.
与此同时,为了适应现在不断扩大的内存和不断增加的处理器数量,进一步 降低暂停时间(pause time),同时兼顾良好的吞吐量。
官方给 G1 设定的目标是在延迟可控的情况下获得尽可能高的吞吐量,所以 才担当起“全功能收集器”的重任与期望。
G1 是一款面向服务端应用的垃圾收集器。
哪它为什么名字叫做 Garbage First(G1)呢?
因为 G1 是一个并行回收器,它把堆内存分割为很多不相关的区域(Region) (物理上不连续的)。使用不同的 Region 来表示 Eden、幸存者 0 区,幸存者 1 区,老年代等。
G1 GC 有计划地避免在整个 Java 堆中进行全区域的垃圾收集。G1 跟踪各 个 Region 里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时 间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收 价值最大的 Region.
由于这种方式的侧重点在于回收垃圾最大量的区间(Region),所以我们给 G1 一个名字:垃圾优先(Garbage First)。
G1(Garbage-First)是一款面向服务端应用的垃圾收集器,主要针对配备 多核 CPU 及大容量内存的机器,以极高概率满足 Gc 停顿时间的同时,还兼具 高吞吐量的性能特征。
G1 收集器可以 “ 建立可预测的停顿时间模型 ”,它维护了一个列表用 于记录每个 Region 回收的价值大小(回收后获得的空间大小以及回收所需时 间的经验值),这样可以保证 G1 收集器在有限的时间内可以获得最大的回收 效率。
如下图所示,G1 收集器收集器收集过程有初始标记、并发标记、最终标记、 筛选回收,和 CMS 收集器前几步的收集过程很相似:
- 初始标记:标记出 GC Roots 直接关联的对象,这个阶段速度较快,需 要停止用户线程,单线程执行。
- 并发标记:从 GC Root 开始对堆中的对象进行可达新分析,找出存活 对象,这个阶段耗时较长,但可以和用户线程并发执行。
- 最终标记:修正在并发标记阶段引用户程序执行而产生变动的标记记录。
- 筛选回收:筛选回收阶段会对各个 Region 的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来指定回收计划(用最少的时间来回收包 含垃圾最多的区域,这就是 Garbage First 的由来——第一时间清理垃圾最多 的区块),这里为了提高回收效率,并没有采用和用户线程并发执行的方式,而 是停顿用户线程。
适用场景: 要求尽可能可控 GC 停顿时间;内存占用较大的应用。可以用-XX:+UseG1GC
使用 G1 收集器,jdk9 默认使用 G1 收集器。
小结:
垃圾回收器
比较底层,了解垃圾回收器的一些种类及实现.
垃圾回收器(具体实现垃圾回收的收集器名称)
垃圾回收器分类
按线程数分,可以分为串行垃圾回收器和并行垃圾回收器
按照工作模式分,可以分为并发式垃圾回收器和独占式垃圾回收器
按工作的内存区间分,又可分为年轻代垃圾回收器和老年代垃圾回收器
垃圾回收器的性能指标
吞吐量:运行用户代码的时间占总运行时间的比例(总运行时间:程序的运
行时间+内存回收的时间)
垃圾收集开销:垃圾收集所用时间与总运行时间的比例。
暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间。
收集频率:相对于应用程序的执行,收集操作发生的频率。
内存占用:Java 堆区所占的内存大小。
快速:一个对象从诞生到被回收所经历的时间。
到此,JVM虚拟机部分已经学习完毕,下一个阶段我们将进入框架的进阶。