设计目的:为了减少GC
原理:可以看作是一个存放可重用对象的值的容器,存放已经分配但暂时不用的对象,在需要用到的时候直接从pool中取。
特点:可伸缩,并发安全 ,在高负载下可以动态的扩容,在不活跃时对象池会收缩
细节:每个P(对应GPM的P)都分配一个本地池,当执行Get或者Put操作的时候,会先将goroutine和某个P的子池关联,再对该子池进行操作。 每个P的子池分为私有对象和共享列表对象,私有对象只能被特定的P访问,共享列表对象可以被任何P访问,需要加锁;
使用场景:用作临时的对象池,适用于储存一些会在goroutine间分享的临时对象,如果要实现连接池的效果,可以用container/list来实现
注意的坑:取出的数据是之前的值,即不会重置前面初始化过的值,需要在put之前写个free函数来重置数据;put之后不要再使用引用的类型,否则会有问题;[]byte过大,再put回去,造成内存浪费,从而导致泄露;可以使用cap判断[]byte大小put放回去,且使用[:0]重置[]byte指针位置;[]byte使用多个容量大小来定义pool变量,以免造成内存浪费;具体参考src/fmt/pring.go的free()和src/net/http/server.go的bufioWriterPool;
例1:
package main
import (
"sync"
"time"
"fmt"
)
var bytePool = sync.Pool{
New: func() interface{} {
b := make([]byte, 1024)
return &b
},
}
func main() {
//defer
//debug.SetGCPercent(debug.SetGCPercent(-1))
a := time.Now().Unix()
for i:=0;i
obj := make([]byte, 1024)
_ = obj
}
b := time.Now().Unix()
for j:=0;j
obj := bytePool.Get().(*[]byte)
_ = obj
bytePool.Put(obj)
}
c := time.Now().Unix()
fmt.Println("without pool ", b - a, "s")
fmt.Println("with pool ", c - b, "s")
}
例2:
var pool = sync.Pool{
New: func() interface{} {
return "123"
},
}
func main() {
t := pool.Get().(string)
fmt.Println(t)
pool.Put("321")
pool.Put("321")
pool.Put("321")
pool.Put("321")
runtime.GC()
time.Sleep(1 * time.Second)
t2 := pool.Get().(string) //拿到幸存者
fmt.Println(t2)
runtime.GC()
time.Sleep(1 * time.Second)
t2 = pool.Get().(string)
fmt.Println(t2)
}