vault backup: 2026-06-07 12:14:39

This commit is contained in:
2026-06-07 12:14:39 +08:00
parent 1a72bc4d82
commit 7ce9b83218
61 changed files with 8409 additions and 14429 deletions
+41 -8
View File
@@ -1,14 +1,18 @@
---
tags:
- Go
- golang
- go原理深入
- 内存管理
tags: [go, golang, go-principle, garbage-collection]
create time: 2026-06-07 16:00
---
# 垃圾回收
# 垃圾回收算法
## 1. 什么是GC
## 概述
本文从 GC 发展史出发,深入解析 Go 的并发三色标记法 + 混合写屏障机制。涵盖引用计数、标记清除、复制法等经典算法对比,以及插入写屏障、删除写屏障、混合写屏障的原理和演进。这是理解 Go 为什么能做到"低停顿、高吞吐"GC 的核心篇章。
> [!question] ❓ 思考
> 为什么 Go 不采用 Java 那样的分代 GC?三色标记在并发的情况下怎么保证不会错误回收还在使用的对象?写屏障是如何在不暂停程序的情况下做到这一点的?
---
GC的全称是 Garbage Collection,字面意思是垃圾回收,其实可以理解为垃圾内存回收。GC是编程语言实现的一种自动内存管理机制,用来找到程序中不再使用的那些“垃圾”内存,然后把它们清理掉,让这些内存重新可用。这里所说的“垃圾”内存更确切一点说其实是堆上的不再使用的内存,因为栈上的内存是由编译器自动分配和释放的,不需要GC参与
@@ -235,13 +239,23 @@ func main() {
* 黑色:已被垃圾收集器访问到的对象,且其引用都已被扫描到,黑色对象中任何一个指针都不可能直接指向白色对象
```mermaid
flowchart LR
White["白色<br/>未访问 / 潜在垃圾"] -->|被根扫描发现| Gray["灰色<br/>已访问,待扫描子对象"]
Gray -->|子对象全部扫描完| Black["黑色<br/>已完全扫描"]
Black -.不可能指向.-> White
style White fill:#fff9c4
style Gray fill:#ffe0b2
style Black fill:#cfd8dc
```
标记过程如下:
1. **初始状态**:所有对象都是白色的
2. **扫描根对象**:从根对象开始扫描,将所有可达对象标记为灰色,并放入待处理集合中
3. **处理灰色对象**:从待处理集合中取出灰色对象,将它们引用的对象标记为灰色,并将这些新标记的对象加入待处理集合中,同时将自身标记为黑色。
3. **处理灰色对象**:从待处理集合中取出灰色对象,将它们引用的对象标记为灰色,同时将自身标记为黑色。
4. **重复扫描**:重复第3步,直到待处理集合为空。此时,所有白色对象都是不可达的垃圾对象,可以进行回收
@@ -313,6 +327,11 @@ func main() {
* 灰色对象与它之间的可达关系的白色对象遭到破坏(灰色对象同时丢失了该白色对象的引用)
> [!warning] ⚠️ 核心矛盾
> 并发三色标记的核心问题就是:用户程序(Mutator)在运行,GC 也在运行。用户程序的指针修改可能在 GC 扫描的间隙"偷偷"把一个黑色对象和白色对象连起来,而灰色对象恰好断开了对同一个白色对象的引用——这就导致白色对象被误杀。
>
> 解决方案只有一个:**引入屏障技术**。
### **5.5 屏障技术**
#### **5.5.1 强弱三色不变性**
@@ -752,6 +771,13 @@ go语言在Go 1.7 之前其实就使用的是 插入写屏障(Dijkstra Write b
**混合写屏障模式下,利用删除写屏障避免了插入写屏障的STW问题(全部三色标记扫描之后,要STW对栈重新进行三色标记扫描),又利用插入写屏障避免了删除写屏障的STW问题(使用删除写屏障之前需要STW垃圾扫描整个栈空间,获取快照,把所有的堆对象都处于灰色保护中),这样就完美解决了屏障技术带来的STW问题**
> [!tip] 💡 理解要点
> 混合写屏障的精妙之处在于:它不是简单地把两种屏障叠加,而是巧妙地利用了两者的互补性——
> - 删除写屏障保证了"旧引用标灰",避免灰色到白色的路径断裂
> - 插入写屏障保证了"新引用也标灰",避免不需要 STW 重扫栈
>
> 两者结合,GC 全程无需全局 STW!
上面只是从感官上分析了插入写屏障和删除写屏障的结合,解决了STW的问题,但其实混合写屏障不仅仅是做了这两点
Go 在Go V1.8版本时候为了简化 GC 的流程,同时减少标记终止阶段的重扫成本,将 Dijkstra 插入屏障和 Yuasa 删除屏障进行混合,引入了混合写屏障机制(hybrid write barrier)。
@@ -909,5 +935,12 @@ GO语言GC总体上来说是采用的并行三色标记法+混合写屏障机制
3. 混合写屏障扫描栈的方式是逐个暂停扫描的,不需要STW
## 关联笔记
- [[hzh/GolangStar/Go语言原理/memory management原理]] — 内存管理三层架构
- [[hzh/GolangStar/Go语言原理/gmp调度原理]] — sysmon 线程如何触发 GC
- [[hzh/GolangStar/Go语言原理/逃逸分析]] — 哪些对象会分配到堆上被 GC
- [[hzh/GolangStar/Go面试题库/垃圾回收面试题]] — GC 相关高频面试题