用golang实现内存池
用golang做一个预分配的内存池,代码可以很小量做到。 实现细节,主要是一个链表,用来保存内存块.
定义2个值:
num 每次需要增长内存池的时候,预分配的内存块数量
size 预分配时,单个内存块的大小
一共两个类型:
Pool 内存池对象,管理grow动作, Get, Put等动作
Buffer 一个链表
初始化时:
type Pool struct {
lock sync.Mutex
free *Buffer
max int
num int
size int
}
// 初始化内存池的时候,调用grow做一次内存预分配
func (p *Pool) init(num, size int) {
p.num = num
p.size = size
p.max = num * size
p.grow()
}
func (p *Pool) grow() {
var (
i int
b *Buffer
bs []Buffer
buf []byte
)
buf = make([]byte, p.max) // 创建一个num * size大小的连续内存
bs = make([]Buffer, p.num) // 创建链表节点
p.free = &bs[0]
b = p.free
for i = 1; i < p.num; i++ { // 完成链表节点的首尾相连,引用前面的大内存块中的逐个内存块
b.buf = buf[(i-1)*p.size : i*p.size]
b.next = &bs[i]
b = b.next
}
b.buf = buf[(i-1)*p.size : i*p.size]
b.next = nil // 这是一个单向链表
return
}
链表对象结构是:
type Buffer struct {
buf []byte
next *Buffer // to next node
}
然后就是两个对外的接口, Get 和 Put
// 获取一个内存块
func (p *Pool) Get() (b *Buffer) {
p.lock.Lock()
if b = p.free; b == nil {
p.grow()
b = p.free
}
p.free = b.next
p.lock.Unlock()
return
}
// 释放一个内存块
func (p *Pool) Put(b *Buffer) {
p.lock.Lock()
b.next = p.free
p.free = b
p.lock.Unlock()
return
}
size的大小就是内存块的大小, 因此应根据实际使用场景变化, 比如用在tcp socket 的write buffer上的时候, 那么size就是你希望能buff住的write buffer大小。