首次提交:初始化项目代码

This commit is contained in:
sunct
2026-07-31 15:18:32 +08:00
commit d6393266b0
193 changed files with 14287 additions and 0 deletions
+365
View File
@@ -0,0 +1,365 @@
package main
import (
"container/list"
"fmt"
"sync"
"sync/atomic"
"time"
)
// 三色标记常量(使用int32以便原子操作)
const (
White int32 = iota // 0: 未标记/垃圾对象
Grey // 1: 待处理态
Black // 2: 完成态/存活对象
)
// Object 模拟堆内存中的引用对象
// 注意:Color字段使用原子操作保护
type Object struct {
ID string
Color int32 // 使用int32支持原子操作
Children []*Object // 子对象用指针,模拟真实引用关系
mu sync.Mutex // 保护Children修改
}
// NewObject 创建新对象,初始为白色
func NewObject(id string) *Object {
return &Object{
ID: id,
Color: White,
Children: make([]*Object, 0),
}
}
// GetColor 安全获取对象颜色(原子读取)
func (o *Object) GetColor() int32 {
return atomic.LoadInt32(&o.Color)
}
// SetColor 安全设置对象颜色(原子写入)
func (o *Object) SetColor(newColor int32) {
atomic.StoreInt32(&o.Color, newColor)
}
// CompareAndSetColor 原子比较并设置颜色(CAS操作)
func (o *Object) CompareAndSetColor(oldColor, newColor int32) bool {
return atomic.CompareAndSwapInt32(&o.Color, oldColor, newColor)
}
// AddChild 线程安全地添加子对象
func (o *Object) AddChild(child *Object) {
o.mu.Lock()
defer o.mu.Unlock()
o.Children = append(o.Children, child)
}
// GetChildren 线程安全地获取子对象
func (o *Object) GetChildren() []*Object {
o.mu.Lock()
defer o.mu.Unlock()
// 创建副本避免并发修改问题
children := make([]*Object, len(o.Children))
copy(children, o.Children)
return children
}
// 模拟写屏障:当黑色对象引用白色对象时,将白色对象标记为灰色
func WriteBarrier(parent *Object, child *Object, grayQueue *list.List, queueMutex *sync.Mutex) {
// 原子读取颜色,避免竞态
parentColor := parent.GetColor()
childColor := child.GetColor()
if parentColor == Black && childColor == White {
// 使用CAS确保颜色转换的原子性
if child.CompareAndSetColor(White, Grey) {
queueMutex.Lock()
grayQueue.PushBack(child)
queueMutex.Unlock()
fmt.Printf("WriteBarrier: [%s](黑)→ [%s](白),强制将[%s]标记为灰色\n",
parent.ID, child.ID, child.ID)
}
}
}
// 辅助方法:递归查找第一个黑色对象,用于模拟业务协程场景
func findBlackObject(objs []*Object) *Object {
for _, obj := range objs {
if obj.GetColor() == Black {
return obj
}
// 递归遍历子对象
children := obj.GetChildren()
if child := findBlackObject(children); child != nil {
return child
}
}
return nil
}
// 辅助方法:递归获取所有对象,模拟堆内存遍历
func getAllObjects(objs []*Object) []*Object {
var all []*Object
visited := make(map[*Object]bool)
var mutex sync.Mutex
var traverse func(*Object)
traverse = func(o *Object) {
mutex.Lock()
if visited[o] {
mutex.Unlock()
return
}
visited[o] = true
mutex.Unlock()
all = append(all, o)
children := o.GetChildren()
for _, child := range children {
traverse(child)
}
}
for _, o := range objs {
traverse(o)
}
return all
}
// 三色标记与清除主流程
func TriColorMarkAndSweep(rootObjects []*Object) ([]*Object, []*Object) {
// 1. 初始化灰色队列和同步锁(保证并发安全)
grayQueue := list.New()
var queueMutex sync.Mutex
// 2. 初始标记阶段(STW):标记根对象
fmt.Println("===== 阶段1:初始标记(STW =====")
for _, root := range rootObjects {
// 原子检查并设置颜色
if root.GetColor() == White {
root.SetColor(Grey)
fmt.Printf("根对象[%s] 白→灰,加入灰色队列\n", root.ID)
queueMutex.Lock()
grayQueue.PushBack(root)
queueMutex.Unlock()
}
}
// 3. 并发标记阶段(无STW)
fmt.Println("\n===== 阶段2:并发标记(无STW =====")
var wg sync.WaitGroup
// 模拟业务协程运行,并发修改引用关系
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(50 * time.Millisecond) // 等待GC标记协程启动并处理部分对象
fmt.Println("\n[业务协程] 正在运行,修改对象引用关系...")
// 模拟并发修改:黑色对象指向新的白色对象
blackObj := findBlackObject(rootObjects)
if blackObj != nil {
newWhiteObj := NewObject("新创建的白色对象")
fmt.Printf("[业务协程] 尝试让黑色对象[%s]引用新白色对象[%s]\n",
blackObj.ID, newWhiteObj.ID)
// 触发写屏障,拦截危险引用
WriteBarrier(blackObj, newWhiteObj, grayQueue, &queueMutex)
// 线程安全地添加子对象
blackObj.AddChild(newWhiteObj)
// 验证写屏障效果
time.Sleep(10 * time.Millisecond)
if newWhiteObj.GetColor() == Grey {
fmt.Printf("[业务协程] 验证: [%s] 已被写屏障保护,状态=灰色\n", newWhiteObj.ID)
} else {
fmt.Printf("[业务协程] 警告: [%s] 未被写屏障保护,状态=%d\n", newWhiteObj.ID, newWhiteObj.GetColor())
}
} else {
fmt.Println("[业务协程] 未找到黑色对象,跳过引用修改")
}
}()
// GC标记协程:遍历灰色队列,处理对象标记
wg.Add(1)
go func() {
defer wg.Done()
for {
var grayObj *Object
// 原子操作获取灰色对象
queueMutex.Lock()
if grayQueue.Len() == 0 {
queueMutex.Unlock()
break
}
// 取出队列头部的灰色对象
elem := grayQueue.Front()
grayObj = elem.Value.(*Object)
grayQueue.Remove(elem)
queueMutex.Unlock()
fmt.Printf("处理灰色对象: [%s] (当前颜色=%d)\n", grayObj.ID, grayObj.GetColor())
// 原子获取子对象列表(避免并发修改)
children := grayObj.GetChildren()
// 遍历当前对象的所有子对象
for _, child := range children {
// 原子检查子对象颜色
if child.GetColor() == White {
// 使用CAS确保状态转换正确
if child.CompareAndSetColor(White, Grey) {
fmt.Printf(" [%s] 引用了 [%s],白→灰,加入队列\n", grayObj.ID, child.ID)
queueMutex.Lock()
grayQueue.PushBack(child)
queueMutex.Unlock()
}
}
}
// 所有子对象处理完成,当前对象转为黑色
// 使用CAS确保从灰色到黑色的转换
if grayObj.CompareAndSetColor(Grey, Black) {
fmt.Printf(" [%s] 所有子对象标记完成,灰→黑\n", grayObj.ID)
} else {
fmt.Printf(" [%s] 颜色转换失败,当前状态=%d\n", grayObj.ID, grayObj.GetColor())
}
time.Sleep(10 * time.Millisecond) // 模拟标记耗时,便于观察流程
}
fmt.Println("灰色队列已空,并发标记阶段完成")
}()
// 等待业务协程和GC标记协程完成
wg.Wait()
// 4. 重新标记阶段(STW):处理写屏障捕获的漏标对象
fmt.Println("\n===== 阶段3:重新标记(STW =====")
queueMutex.Lock()
for grayQueue.Len() > 0 {
elem := grayQueue.Front()
obj := elem.Value.(*Object)
grayQueue.Remove(elem)
if obj.GetColor() == Grey {
// 遍历子对象,确保标记完整
children := obj.GetChildren()
for _, child := range children {
if child.GetColor() == White {
if child.CompareAndSetColor(White, Grey) {
fmt.Printf("重新标记补标: [%s] 引用的 [%s](白→灰)\n", obj.ID, child.ID)
grayQueue.PushBack(child)
}
}
}
// 标记完成后转为黑色
obj.SetColor(Black)
fmt.Printf("重新标记确认: 对象[%s]为存活,灰→黑\n", obj.ID)
}
}
queueMutex.Unlock()
// 5. 收集所有堆对象(包括未被根对象引用的孤立对象)
fmt.Println("\n===== 阶段4:收集所有堆对象 =====")
allObjects := getAllObjects(rootObjects)
// 6. 创建真正的孤立对象(无根可达)
trueGarbage1 := NewObject("真正的孤立对象-临时会话")
trueGarbage2 := NewObject("真正的孤立对象-过期验证码")
// 添加到所有对象集合,模拟真实堆内存
allObjects = append(allObjects, trueGarbage1, trueGarbage2)
// 7. 并发清除阶段:回收白色对象
fmt.Println("\n===== 阶段5:并发清除(无STW =====")
var garbageObjects []*Object
var liveObjects []*Object
for _, obj := range allObjects {
if obj.GetColor() == White {
garbageObjects = append(garbageObjects, obj)
fmt.Printf("对象[%s] 为白色,判定为垃圾,执行回收\n", obj.ID)
} else {
liveObjects = append(liveObjects, obj)
fmt.Printf("对象[%s] 为存活对象(颜色=%d),保留\n", obj.ID, obj.GetColor())
// 重置为白色,为下一次GC做准备
obj.SetColor(White)
}
}
return garbageObjects, liveObjects
}
func main() {
// ========== 构建对象引用链路,模拟真实业务场景 ==========
// 根对象:模拟全局变量/栈帧变量
root1 := NewObject("根对象-用户服务")
root2 := NewObject("根对象-订单服务")
// 构建引用链路:用户服务 → 用户缓存 → 具体用户
userCache := NewObject("用户缓存")
user1 := NewObject("用户-张三")
user2 := NewObject("用户-李四")
userCache.AddChild(user1)
userCache.AddChild(user2)
root1.AddChild(userCache)
// 构建引用链路:订单服务 → 订单缓存 → 具体订单
orderCache := NewObject("订单缓存")
order1 := NewObject("订单-202311001")
orderCache.AddChild(order1)
root2.AddChild(orderCache)
// 创建真实可访问对象
validObj := NewObject("有效会话数据")
order1.AddChild(validObj)
// ========== 执行三色标记GC流程 ==========
rootObjects := []*Object{root1, root2}
garbage, live := TriColorMarkAndSweep(rootObjects)
// ========== 输出GC执行结果 ==========
fmt.Printf("\n===== GC执行完成,统计结果 =====\n")
fmt.Printf("存活对象数量: %d\n", len(live))
fmt.Printf("垃圾对象数量: %d\n", len(garbage))
fmt.Println("\n垃圾对象详情:")
for _, g := range garbage {
fmt.Printf("- %s (最终颜色=%d)\n", g.ID, g.GetColor())
}
// 验证关键对象状态
fmt.Println("\n===== 关键对象状态验证 =====")
expectedGarbage := []string{"真正的孤立对象-临时会话", "真正的孤立对象-过期验证码"}
found := 0
for _, g := range garbage {
for _, expected := range expectedGarbage {
if g.ID == expected {
fmt.Printf("✓ 对象[%s] 被正确识别为垃圾对象 (颜色=%d)\n", g.ID, g.GetColor())
found++
}
}
}
fmt.Printf("垃圾对象识别准确率: %.0f%% (%d/%d)\n", float64(found)/float64(len(expectedGarbage))*100, found, len(expectedGarbage))
// 验证写屏障对象状态
fmt.Println("\n===== 写屏障保护验证 =====")
newObjFound := false
for _, l := range live {
if l.ID == "新创建的白色对象" {
newObjFound = true
if l.GetColor() == Black {
fmt.Printf("✓ 对象[%s] 被正确标记为存活 (颜色=%d),写屏障保护成功\n", l.ID, l.GetColor())
} else {
fmt.Printf("✗ 对象[%s] 未被正确标记 (颜色=%d),写屏障保护失败\n", l.ID, l.GetColor())
}
}
}
if !newObjFound {
fmt.Println("⚠ 未找到写屏障创建的新对象,可能未被正确处理")
}
}