---
title: JVM垃圾回收算法
published: 2025-07-18
description: ''
image: ''
tags: [JVM,垃圾回收，分代回收]
category: 'Java > JVM'
draft: false 
lang: ''
---
# 垃圾回收算法

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nn4ww-1.webp)

[【Java虚拟机】JVM垃圾回收机制和常见回收算法原理-腾讯云开发者社区-腾讯云](https://cloud.tencent.com/developer/article/2292267)

### **垃圾回收机制**

**（1）什么是垃圾回收机制（Garbage Collection， 简称GC)**

- 指自动管理动态分配的内存空间的机制，自动回收不再使用的内存，以避免内存泄漏和内存溢出的问题
- 最早是在1960年代提出的，程序员需要手动管理内存的分配和释放
- 这往往会导致内存泄漏和内存溢出等问题，同时也增加了程序员的工作量，特别是C++/C语言开发的时候
- Java语言是最早实现垃圾回收机制的语言之一，其他编程语言，如C#、Python和Ruby等，也都提供了垃圾回收机制

**（2）JVM自动垃圾回收机制**

- 指Java虚拟机在运行Java程序时，自动回收不再使用的对象所占用的内存空间的过程
- Java程序中的对象，一旦不再被引用会被标记为垃圾对象，JVM会在适当的时候自动回收这些垃圾对象所占用的内存空间
- 优点
- 减少了程序员的工作量，不需要手动管理内存
- 动态地管理内存，根据应用程序的需要进行分配和回收，提高了内存利用率
- 避免内存泄漏和野指针等问题，增加程序的稳定性和可靠
- 缺点
- 垃圾回收会占用一定的系统资源，可能会影响程序的性能
- 垃圾回收过程中会停止程序的执行，可能会导致程序出现卡顿等问题
- **不一定能够完全解决内存泄漏等问题，需要在编写代码时注意内存管理和编码规范**

---

# 垃圾回收算法

## 引用计数法

跟踪每个对象被引用的次数，当引用次数为0 的时候，可以将该对象回收。

优点是实现简单，缺点是循环引用没办法回收，而且引用计数器消耗大。

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nn7eb-1.webp)

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nngi3-1.webp)

## **可达性分析算法**

- 可达性分析算法的基本思想是通过一系列的“GC Roots”对象作为起点进行搜索。
- 如果“GC Roots”和一个对象之间没有可达路径，则称该对象是不可达的，不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。
- 被判定为不可达的对象要成为回收对象，要至少经历两次标记过程。
- 如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性，则基本上就真的成为可回收对象了。

通过一系列称为“GC Roots”的对象作为起始点，从这些节点开始向下搜索，搜索走过的路径称为“引用链”，当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时，证明此对象不可用。

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nnmfv-1.webp)

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nnpgs-1.webp)

### 什么是GC ROOT

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nntly-1.webp)

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nnyst-1.webp)

## **垃圾回收算法之标记-复制算法**

- 标记算法是一种常见的垃圾回收算法，它的基本思路是将Java堆分为两个区域：一个活动区域和一个空闲区域
- 在垃圾回收过程中，首先标记所有被引用的对象
- 然后将所有被标记的对象复制到空闲区域中，最后交换两个区域的角色，完成垃圾回收
- 标记复制算法的详细实现步骤
  - 将Java堆分为两个区域：一个活动区域和一个空闲区域，初始时，所有对象都分配在活动区域中
  - 从GC Roots对象开始，遍历整个对象图，标记所有被引用的对象
  - 对所有被标记存活的对象进行遍历，将它们复制到空闲区域中，并更新所有指向它们的引用，使它们指向新的地址
  - 对所有未被标记的对象进行回收，将它们所占用的内存空间释放
  - 交换活动区域和空闲区域的角色，空闲区域变为新的活动区域，原来的活动区域变为空闲区域
  - 当空闲区域的内存空间不足时，进行一次垃圾回收，重复以上步骤。
- 优点
  - 如果内存中的垃圾对象较多，需要复制的对象就较少，则效率高
  - 清理后，内存碎片少
- 缺点
  - 标记复制算法的效率较高，但是预留一半的内存区域用来存放存活的对象，占用额外的内存空间
  - 如果出现存活对象数量比较多的时候，需要复制较多的对象 效率低
  - 假如是在老年代区域，99%的对象都是存活的，则性能底，所以老年代不适合这个算法

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10no08y-1.webp)

复制过程如下，GC会将五个存活对象复制到to区，并且保证在to区内存空间上的连续性。

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10no6pp-1.webp)

最后，将from区中的垃圾对象清除。

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nojzj-1.webp)

## **垃圾回收算法之标记-整理算法**

标记-整理算法（Mark-Compact Algorithm） 是一种常见的垃圾回收（GC）算法，主要用于解决 标记-清除算法（Mark-Sweep） 产生的内存碎片问题。它通常被用于 Java 的老年代（Old Generation）垃圾回收中。

标记-整理算法主要分为两大阶段：

标记阶段（Mark Phase）

和标记-清除算法一样，从 GC Roots 出发，遍历所有可达对象，并将其标记为“存活”状态。

整理阶段（Compact Phase）

将所有存活对象向内存的一端移动（通常是低地址方向）。

移动后会更新对象引用地址，以保证程序继续正确运行。

移动完成后，直接清理边界以后的内存空间。

![](https://blog.meowrain.cn/api/i/2025/07/18/10pzxij-1.webp)

| **特点** | **标记-清除算法**   | **标记-整理算法**   |
| ------ | ------------- | ------------- |
| 内存碎片   | 会产生碎片         | 不会产生碎片        |
| 效率     | 清除快（只清除不可达对象） | 较慢（需要移动对象）    |
| 适用场景   | 适用于对象回收率较高的情况 | 适用于对象存活率较高的情况 |

## 垃圾回收算法之-分代算法

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10noe2w-1.webp)

新生代分为eden区、from区、to区，老年代是一整块内存空间

分代算法将内存区域分为两部分：新生代和老年代。

根据新生代和老年代中对象的不同特点，使用不同的GC算法。

新生代对象的特点是：创建出来没多久就可以被回收（例如虚拟机栈中创建的对象，方法出栈就会销毁）。也就是说，每次回收时，大部分是垃圾对象，所以新生代适用于复制算法。

老年代的特点是：经过多次GC，依然存活。也就是说，每次GC时，大部分是存活对象，所以老年代适用于标记压缩算法。

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nomg3-1.webp)

![image.png](https://blog.meowrain.cn/api/i/2025/07/18/10nozio-1.webp)

### 分代算法执行过程

---
