# JVM垃圾回收算法

> 2024.1.1 突然想到的
>
> 今天下午洗碗的时候,发现我洗碗的方式和垃圾回收的算法**好像**啊! 我的洗碗步骤如下:
> 1. 将所有的碗移到一个水池A中 (共有2个池子且里面都有碗) (只移动)
> 2. 把每一个碗上的食物使用清水清洗掉,放到另一个池子B中 —— 轻量级清洗
> 3. 将B池子中的每一个碗使用洗洁精清洗后放到A池中 —— 精洗,但这步还没有使用清水冲洗
> 4. 将A池中的每一个盘子用清水清洗干净 (清理)
> 5. 等都用清水冲洗完之后,碗就清洗干净了,放到厨台上备用 (整理)

## 有哪些垃圾回收算法?
### 标记-清除(Mark—Sweep)
被誉为现代垃圾回收算法的思想基础

标记-清除算法采用从根集合进行扫描，对存活的对象标记，标记完毕后，再扫描整个空间中未被标记的对象，进行回收。

标记-清除算法不需要进行对象的移动，并且仅对不存活的对象进行处理，在存活对象比较多的情况下极为高效，但由于标记-清除算法直接回收不存活的对象，因此会造成内存碎片

![](/software-engineer/drawio/Moatkon-OldGenerationGC.drawio.svg)

### 复制算法(Copying)
该算法的提出是为了克服句柄的开销和**解决堆碎片**的垃圾回收。建立在存活对象少，垃圾对象多的前提下。

此算法每次只处理正在使用中的对象，因此复制成本比较小，同时复制过去后还能进行相应的内存整理，不会出现碎片问题。但缺点也是很明显，就是需要两倍内存空间。

![](/software-engineer/drawio/Moatkon-YongGenerationMinorGC.drawio.svg)

### 标记-整理
> 又叫标记-压缩算法(Mark-Compact),又或者叫 标记清除压缩(MarkSweepCompact)

此算法是结合了“标记-清除”和“复制算法”两个算法的优点。避免了“标记-清除”的碎片问题，同时也避免了“复制”算法的空间问题。

标记-整理算法采用标记-清除算法一样的方式进行对象的标记，但在清除时不同，<span style="color:red">在回收不存活的对象占用的空间后，会将所有的存活对象往左端空闲空间移动，并更新对应的指针。</span>

**标记-整理算法是在标记-清除算法的基础上，又进行了对象的移动，因此成本更高，但是却解决了内存碎片的问题**。

### 分代回收策略(Generational Collecting)
**算法思路**:   
基于这样的事实：不同的对象的生命周期是不一样的。因此，不同生命周期的对象可以采取不同的回收算法，以便提高回收效率

**实际操作**:   
新生代由于其对象存活时间短，且需要经常gc，因此采用效率较高的**复制算法**

老年代和永久代因为其存活对象时间长，因此使用**标记清除**或**标记整理算法**


## JVM常用的垃圾收集器
1. Serial/Serial Old：单线程垃圾回收器
2. ParNew：多线程的垃圾回收器(Serial 的多线程版本)
3. Parallel Scavenge/Parallel Old：吞吐量优先的垃圾回收器 **JDK8 默认的垃圾回收器**
4. CMS：**最小等待时间**优先的垃圾收集器
5. G1：**可控垃圾回收时间**的垃圾收集器 **JDK 9 之后(HotSpot)默认的垃圾回收器**
6. ZGC：停顿时间超短(不超过 10ms)的情况下尽量提高垃圾回收吞吐量的垃圾收集器 **JDK 15 之后默认的垃圾回收器**

:::note
- 串行垃圾收集器：`-XX:+UseSerialGC`
- **并行垃圾收集器**：`-XX:+UseParallelGC`
- CMS 垃圾收集器：`-XX:+UseConcMarkSweepGC`
- **G1 垃圾收集器**：`-XX:+UseG1GC`
> 有次面试有被问到有哪些垃圾回收器
:::

## ZGC
ZGC(Z Garbage Collector)是一种低延迟的垃圾回收器，是 JDK 11 引入的一项垃圾回收技术。**它主要针对大内存、多核心的应用场景，旨在减少垃圾回收带来的停顿时间**

#### ZGC核心技术
1. 并发标记：ZGC 采用增量式并发标记算法来实现并发垃圾回收。它不会在标记阶段产生长时间停顿，可以与用户线程并发运行。
2. 粉碎压缩：ZGC 采用粉碎压缩算法来避免产生内存碎片。它会将内存按照特定大小(例如 2MB)分为多个区域，然后将存活对象连续放置在相邻区域，释放掉边界外的内存空间。这可以最大限度减少内存碎片。
3. 直接内存映射：ZGC 会直接映射内存空间，而不需要进行内存分配。这可以避免统计堆内存碎片情况所带来的性能消耗。
4. 微任务：ZGC 采用了微任务(Microtasks)机制来增量完成垃圾回收工作，从而不会产生长时间停顿。它会将总工作分割为多个微任务，这些微任务会在安全点(Safepoint)之间执行。
5. 可扩展的堆内存：ZGC 不需要指定最小堆(Xmn)和最大堆(Xmx)大小，它可以跟踪堆内存变化并根据需要动态调整堆空间大小。这使得 ZGC 可以支持将近 4TB 的堆内存。
6. 可插拔组件：ZGC 是一个独立的 GC 组件，它不依赖于 Gradle 等构建工具，可以与不同的工具或框架一起使用，这增强了其可移植性。

以上技术使ZGC达成毫秒级的停顿和大内存的支持