NOTE
7.10 3.垃圾回收器
1. JVM实际采用的垃圾回收算法:分代收集 根据对象的存活时间把内存分成新生代和老年代 - 新生代的特点是每次回收只有少量对象存活,因此采用改进的复制算法 改进的复制算法把内存空间分为Eden和Survivor区(8:1:1),只有10%的空间被浪费 - 老年代的特点是有大量对象存活,采用标记清除
这是历史学习笔记,可能存在过时或不完整的理解。
1. JVM实际采用的垃圾回收算法:分代收集
根据对象的存活时间把内存分成新生代和老年代
- 新生代的特点是每次回收只有少量对象存活,因此采用改进的复制算法 改进的复制算法把内存空间分为Eden和Survivor区(8:1:1),只有10%的空间被浪费
- 老年代的特点是有大量对象存活,采用标记清除、标记整理算法
2. 垃圾收集器分类
2.1. 四大类七种垃圾回收器
- Serial:单线程执行垃圾回收,同时暂停所有的用户线程
- 新生代:Serial收集器
- 老年代:Serial Old收集器
- Parallel:多线程执行垃圾回收,同时暂停所有的用户线程
- 新生代:ParNew收集器、Parallel Scavenge收集器
- 老年代:Parallel Old收集器
- CMS:多线程执行垃圾回收,不需要暂停用户线程
- G1:

2.1.1. 如何开启
2.2. CMS详解
- 初始标记(initial mark):单线程执行且STW,但仅仅把GC Roots的直接关联可达的对象给标记一下,由于直接关联对象比较小,所以这里的速度非常快。
- 并发标记(concurrent mark):多线程执行但不用STW,对于初始标记过程所标记的初始标记对象,进行并发追踪标记,此时其他线程仍可以继续工作。此处时间较长,但不停顿。
- 重新标记(remark):单线程执行且STW,在并发标记的过程中,由于可能还会产生新的垃圾,所以此时需要重新标记新产生的垃圾。此处执行并行标记,与用户线程不并发,所以依然是“Stop The World”,时间比初始时间要长一点。
- 并发清除(concurrent sweep):多线程执行但不用STW,并发清除之前所标记的垃圾。其他用户线程仍可以工作,不需要停顿。
2.2.1. 日志分析
2.3. G1详解
-
内存划分:宏观上看不在是年轻代、老年代的划分,分成N块region,每一块都有分代属性

-
整体上使用标记整理,从而避免了内存碎片,局部使用复制算法
-
G1可以指定期望的停顿时间
-
对于每一块的回收过程如下:
- 初始标记(initial mark):单线程执行且STW,标记了从GC Root开始直接关联可达的对象。
- 并发标记(concurrent marking):多线程执行但不用STW,并发标记初始标记的对象,此时用户线程依然可以执行。
- 最终标记(Remark):单线程执行且STW,,并发标记过程中可能产生新的垃圾,在标记一次
- 筛选回收(Live Data Counting And Evacuation):多线程执行但不用STW,评估标记垃圾,根据时间来筛选回收哪些垃圾
2.4. CMS vs G1
| CMS | G1 | |
|---|---|---|
| 使用范围 | 老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用 | 收集范围是老年代和新生代。不需要结合其他收集器使用 |
| 目标 | 以最小的停顿时间为目标 | 可预测垃圾回收的停顿时间 |
| 内存碎片 | 使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片 | “标记-整理”算法,进行了空间整合,降低了内存空间碎片。 |
| 垃圾回收的过程不一样 | 2.2. CMS详解 | 2.3. G1详解 |