设计目的:为了减少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)

}