文章目录
- 垃圾回收机制
-
- [1. 分代收集](#1. 分代收集)
- [2. 标记复制](#2. 标记复制)
- [3. 标记清除](#3. 标记清除)
- [4. 标记压缩(整理)](#4. 标记压缩(整理))
- 垃圾回收器
-
- [1. Serial / Serial Old](#1. Serial / Serial Old)
- [2. Parallel Scavenge](#2. Parallel Scavenge)
- [3. ParNew收集器](#3. ParNew收集器)
- [4. CMS收集器](#4. CMS收集器)
- [5. G1收集器](#5. G1收集器)
- 参考链接
垃圾回收机制
1. 分代收集
- 分代收集(Generational Collector )算法就是其中一种针对
GC
性能优化算法,将堆内存划分为新生代、老年代。 - 在分代收集算法中,对象的存储具有以下特点:
- 对象优先在 Eden 区分配。
- 大对象直接进入老年代。
- 长期存活的对象将进入老年代,默认为 15 岁。
- 基本概念 :
- 对象的生命周期:每经历一次GC,对象年龄 + 1。
- 伊甸区:是对象诞生的地方。经过经验的推算,大部分对象的生命基本活不过1岁。
- 生存区:活过了1岁,但大部分也活不到成年15岁。这些对象每经历一次 GC,会在 SA 和 SB 之间反复横跳。
- 老年区:极少数成年的对象 或者 大对象会被一开始放在这儿。
2. 标记复制
- 按内存容量将内存划分为等大小的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉。
- 虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是可用内存被压缩到了原本的一半。且存活对象增多的话,Copying算法的效率会大大降低。
3. 标记清除
- 分为两个阶段:标注和清除。标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。
- 最大的问题是内存碎片化严重,后续可能发生大对象不能找到可利用空间的问题。
4. 标记压缩(整理)
标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象。
垃圾回收器
1. Serial / Serial Old
- Serial工作在新生代垃圾回收, Serial Old工作在老年代垃圾回收,一般作为CMS并发收集失败后的备选回收方案。
- 当进行工作的时候,用户线程全部暂停,等它工作完成后,用户线程才允许继续工作。
简写: Serial收集器:全部暂停,直到收集结束。使用复制算法,响应速度快,没有线程交互开销,简单高效,额外内存消耗最小,适合用于单核cpu环境下client模式,体验会差一点,但只要不频繁发生收集,也可以接受。
2. Parallel Scavenge
-
ParNew收集器实质上是Serial收集器的多线程并行版本,除了同时使用多条线程进行垃圾收集之
外,其余的行为包括Serial收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一致,在实现上这两种收集器也共用了相当多的代码。
-
特点:
- 多线程
- STW相对少点
- 关注吞吐量,高效率利用CPU
3. ParNew收集器
- 和Parallel Scavenge收集器一样,都是多线程进行回收,不过主要是和CMS收集器配合使用
4. CMS收集器
- CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网网站或者基于浏览器的B/S系统的服务端上,这类应用通常都会较为关注服务的响应速度,希望系统停顿时间尽可能短,以给用户带来良好的交互体验。CMS收集器就非常符合这类应用的需求。
- 垃圾回收过程:
- 初始标记 (initial-mark ):initial-mark 需要
Stop The World
(简写为STW
,就是停止所有用户线程),初始标记仅仅只是标记一下GC Roots
能直接关联到的对象,速度很快。这个GC Roots
仅仅是老年代的GC Roots
,同时初始标记不用去解决跨代引用(新生代引用老年代)问题,这个问题需要留在 remark 阶段去解决。暂停所有用户线程,只标记GC Roots
直接引用的对象 - 并发标记 (concurrent-mark):GC线程和用户线程同时工作,GC线程从gc goot开始遍历整个对象图
- 重新标记 (remark ):remark 阶段需要
STW
,这个阶段会比 initial-mark 阶段要长,但远比 concurrent-mark 阶段要短。主要是为了标记前面并发阶段,用户线程继续运作而导致漏标、少标的对象。 - 并发清理 (concurrent-sweep ):concurrent-sweep 阶段不需要
Stop The World
,上一阶段记录了本次 GC 的内存区域,标记整理算法并不用一一去回收已死对象,只需要把已死对象所在内存区域重新加入空闲列表即可。由于是和用户线程并发执行,这时新晋对象进入老年代所在的内存范围不在 GC 内存范围之内,所以它没被标记也不会被参与回收。 - 并发重置 (concurrent reset):重新设置 CMS 相关的各种状态及数据结构,为下一个垃圾收集周期做好准备,将存活对象上的标记给移除掉,避免影响下次GC
- 初始标记 (initial-mark ):initial-mark 需要
- 特点:
- STW时间短
- 产生浮动垃圾
- 空间碎片(可以在清理后开启空间压缩处理)
- 如果一直清理不干净,会导致频繁出现
full GC
最终导致并发收集失败,采用备选方案 Serial old单线程收集
- CMS 很多阶段是和用户线程并发执行,这些阶段会源源不断有新的对象产生,从而触发 YGC,如果需要搬进老年代的对象大于老年代的可用空间,则会触发 Full GC。
5. G1收集器
-
Garbage First (简称G1)收集器是垃圾收集器技术发展历史上的里程碑式的成果,它开创了收集器面向局部收集的设计思路和基于Region的内存布局形式。全功能的垃圾收集器 ,主要面向服务端应用的垃圾收集器,具备较高吞吐率。
-
调整:
- 在新生代和老年代的基础上,加了一个存放大对象的区域
- 将整个内存区域全部划分成大小相同的网格(region ),最多有2048个region
- 每个region 都有可能存储新生代或老年代或大对象
- 大对象的定义是超过region 的50%
- 如果一个大对象存放不下,那么就跨越多个region存放
- 可以通过参数控制停顿时间长短
-
回收过程:
- 初始标记
- 并发标记
- 最终标记
- 筛选回收
-
特点:
- 并发和并行
- 空间整合
- 可预测的停顿