首次提交:初始化项目代码
This commit is contained in:
@@ -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("⚠ 未找到写屏障创建的新对象,可能未被正确处理")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user