bufpool 脏数据例子

package main

import (
	"fmt"
	"math/rand"
	"runtime"
	"sync"
	"time"
)

var bufPool = &sync.Pool{
	New: func() any {
		buffer := make([]byte, 0, 2)
		return &buffer
	},
}

func main() {
	// 1. 将 GOMAXPROCS 设置为较小值(如 2),强制 goroutine 在少量 P 上高频切换,
	// 增加对象进入全局共享队列的概率。
	runtime.GOMAXPROCS(2)
	var wg sync.WaitGroup
	concurrency := 1000 // 高并发数
	iterations := 100   // 每个 goroutine 循环次数
	for i := 0; i < concurrency; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			for j := 0; j < iterations; j++ {
				bufPtr := bufPool.Get().(*[]byte)
				buf := *bufPtr
				fmt.Printf("cap is %d \n", cap(buf))
				// 【故意不重置】模拟忘记 buf = buf[:0] 的致命错误
				// buf = buf[:0]
				// 写入特定标识:Goroutine ID + 循环次数
				marker := fmt.Sprintf("[G%d-I%d-%s]", id, j,RandRandomLenStr(5,100))
				buf = append(buf, []byte(marker)...)
				// 检查脏数据:如果切片长度大于当前写入标识的长度,
				// 说明前面有上一次残留的数据!
				if len(buf) > len(marker) {
					fmt.Printf("💥 抓到脏数据! Goroutine %d 拿到了残留内容: %s\n", id, string(buf))
					// 发现一次即可,防止控制台被刷爆
					wg.Done() // 抵消一次 wg.Add
					return
				}
				// 归还到池中(没有重置长度)
				*bufPtr = buf
				bufPool.Put(bufPtr)
			}
		}(i)
	}
	wg.Wait()
	fmt.Println("测试完成,如果没有打印💥,说明运气好没触发,可以尝试增加并发数。")
}

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func RandRandomLenStr(minLen, maxLen int) string {
	if minLen <= 0 || maxLen < minLen {
		return ""
	}
	rand.Seed(time.Now().UnixNano())
	// 随机长度
	length := rand.Intn(maxLen-minLen+1) + minLen
	b := make([]byte, length)
	for i := range b {
		b[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	return string(b)
}
posted @ 2026-07-17 16:43  rincloud  阅读(3)  评论(0)    收藏  举报